c++17 string_view

 

 

 

string_view: No such file or directory

 

 std::string_view is not available in GCC until version 7.

 

root@ubuntu:~/c++# gcc --version
gcc (Ubuntu/Linaro 5.5.0-12ubuntu1) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

root@ubuntu:~/c++# 

 

 

configure: error: Building GCC requires GMP 4.2+, MPFR 2.4.0+ and MPC 0.8.0+.

 

root@cloud:~/gcc-7.5.0# ./contrib/download_prerequisites
2021-07-02 15:02:50 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 [2383840] -> "./gmp-6.1.0.tar.bz2" [1]
2021-07-02 15:02:59 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 [1279284] -> "./mpfr-3.1.4.tar.bz2" [1]
2021-07-02 15:03:05 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz [669925] -> "./mpc-1.0.3.tar.gz" [1]
2021-07-02 15:03:15 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.16.1.tar.bz2 [1626446] -> "./isl-0.16.1.tar.bz2" [1]
gmp-6.1.0.tar.bz2: OK
mpfr-3.1.4.tar.bz2: OK
mpc-1.0.3.tar.gz: OK
isl-0.16.1.tar.bz2: OK
All prerequisites downloaded successfully.
root@cloud:~/gcc-7.5.0# 

 

 

root@cloud:~/gcc-7.5.0# mkdir  gcc-build-7.5
root@cloud:~/gcc-7.5.0# cd gcc-build-7.5/
root@cloud:~/gcc-7.5.0/gcc-build-7.5# ../configure --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --enable-gnu-indirect-function --with-tune=generic --disable-multilib 

 

 

root@cloud:~/gcc-7.5.0# ./contrib/download_prerequisites
2021-07-02 15:02:50 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 [2383840] -> "./gmp-6.1.0.tar.bz2" [1]
2021-07-02 15:02:59 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 [1279284] -> "./mpfr-3.1.4.tar.bz2" [1]
2021-07-02 15:03:05 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz [669925] -> "./mpc-1.0.3.tar.gz" [1]
2021-07-02 15:03:15 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.16.1.tar.bz2 [1626446] -> "./isl-0.16.1.tar.bz2" [1]
gmp-6.1.0.tar.bz2: OK
mpfr-3.1.4.tar.bz2: OK
mpc-1.0.3.tar.gz: OK
isl-0.16.1.tar.bz2: OK
All prerequisites downloaded successfully.
root@cloud:~/gcc-7.5.0# cd -
/root/gcc-7.5.0/gcc-build-7.5
root@cloud:~/gcc-7.5.0/gcc-build-7.5# ../configure --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --enable-gnu-indirect-function --with-tune=generic --disable-multilib   
checking build system type... aarch64-unknown-linux-gnu
checking host system type... aarch64-unknown-linux-gnu
checking target system type... aarch64-unknown-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
checking whether ln works... yes
checking whether ln -s works... yes
checking for a sed that does not truncate output... /bin/sed
checking for gawk... gawk
checking for libatomic support... yes
checking for libcilkrts support... no
checking for libitm support... yes
checking for libsanitizer support... yes
checking for libvtv support... yes
checking for libmpx support... no
checking for libhsail-rt support... no

 

 

checking if mkdir takes one argument... no
This target does not support --with-tune.
Valid --with options are: abi cpu arch
Makefile:4282: recipe for target 'configure-stage1-gcc' failed
make[2]: *** [configure-stage1-gcc] Error 1
make[2]: Leaving directory '/root/gcc-7.5.0/gcc-build-7.5'
Makefile:25895: recipe for target 'stage1-bubble' failed
make[1]: *** [stage1-bubble] Error 2
make[1]: Leaving directory '/root/gcc-7.5.0/gcc-build-7.5'
Makefile:939: recipe for target 'all' failed
make: *** [all] Error 2
root@cloud:~/gcc-7.5.0/gcc-build-7.5# 

 

 

configure的最后一个参数是关闭32位库,只编译64位库, 。如果想要同时编译32位和64位,可以使用-enable-multilib
../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib
 

 编译通过

make install

 

 

root@cloud:~/gcc-7.5.0/gcc-build-7.5# ls /usr/local/bin | grep gcc
aarch64-unknown-linux-gnu-gcc
aarch64-unknown-linux-gnu-gcc-7.5.0
aarch64-unknown-linux-gnu-gcc-ar
aarch64-unknown-linux-gnu-gcc-nm
aarch64-unknown-linux-gnu-gcc-ranlib
gcc
gcc-ar
gcc-nm
gcc-ranlib

 

-rwxr-xr-x 3 root root 5771384 Jul  2 17:43 /usr/local/bin/aarch64-unknown-linux-gnu-gcc-7.5.0
root@cloud:~/gcc-7.5.0/gcc-build-7.5# ls -al  /usr/local/bin/aarch64-unknown-linux-gnu-gcc
-rwxr-xr-x 3 root root 5771384 Jul  2 17:43 /usr/local/bin/aarch64-unknown-linux-gnu-gcc
root@cloud:~/gcc-7.5.0/gcc-build-7.5# ls -al  /usr/local/bin/gcc
-rwxr-xr-x 3 root root 5771384 Jul  2 17:43 /usr/local/bin/gcc
root@cloud:~/gcc-7.5.0/gcc-build-7.5#   /usr/local/bin/gcc -v
Using built-in specs.
COLLECT_GCC=/usr/local/bin/gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/aarch64-unknown-linux-gnu/7.5.0/lto-wrapper
Target: aarch64-unknown-linux-gnu
Configured with: ../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib
Thread model: posix
gcc version 7.5.0 (GCC) 
root@cloud:~/gcc-7.5.0/gcc-build-7.5# 

 

root@cloud:~/gcc-7.5.0/gcc-build-7.5# find /usr -name "libstdc++.so*"
/usr/local/lib64/libstdc++.so
/usr/local/lib64/libstdc++.so.6.0.24-gdb.py
/usr/local/lib64/libstdc++.so.6.0.24
/usr/local/lib64/libstdc++.so.6
/usr/lib/gcc/aarch64-linux-gnu/5/libstdc++.so
/usr/lib/gcc/aarch64-linux-gnu/7/libstdc++.so
/usr/lib/aarch64-linux-gnu/libstdc++.so.6.0.25
/usr/lib/aarch64-linux-gnu/libstdc++.so.6
/usr/share/gdb/auto-load/usr/lib/aarch64-linux-gnu/libstdc++.so.6.0.25-gdb.py
root@cloud:~/gcc-7.5.0/gcc-build-7.5# 

 

 

 

 g++ -O0 -o static_str str_vier.cpp -std=c++17 -g && objdump -S -t -D static_str > static_str.s

#include<string>
#include<string_view>
using namespace std;
int main()
{
  40150c:       a9b87bfd        stp     x29, x30, [sp, #-128]!
  401510:       910003fd        mov     x29, sp
  401514:       f9000bf3        str     x19, [sp, #16]
        //指针指向静态字符串
        const char* str_ptr = "this is a static string";
  401518:       90000000        adrp    x0, 401000 <_init-0x2c0>
  40151c:       913ee000        add     x0, x0, #0xfb8
  401520:       f9003fa0        str     x0, [x29, #120]

        //字符串数组
        char str_array[] = "this is a static string";
  401524:       90000000        adrp    x0, 401000 <_init-0x2c0>
  401528:       913ee000        add     x0, x0, #0xfb8
  40152c:       910163a2        add     x2, x29, #0x58
  401530:       aa0003e3        mov     x3, x0
  401534:       a9400460        ldp     x0, x1, [x3]
  401538:       a9000440        stp     x0, x1, [x2]
  40153c:       f9400860        ldr     x0, [x3, #16]
  401540:       f9000840        str     x0, [x2, #16]
        //std::string
        std::string str = "this is a static string";
  401544:       9101c3a0        add     x0, x29, #0x70
  401548:       97ffffa6        bl      4013e0 <_ZNSaIcEC1Ev@plt>
  40154c:       9101c3a2        add     x2, x29, #0x70
  401550:       90000000        adrp    x0, 401000 <_init-0x2c0>
  401554:       913ee001        add     x1, x0, #0xfb8
  401558:       9100e3a0        add     x0, x29, #0x38
  40155c:       94000075        bl      401730 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_>
  401560:       9101c3a0        add     x0, x29, #0x70
  401564:       97ffff8b        bl      401390 <_ZNSaIcED1Ev@plt>
        //std::string_view
        std::string_view sv = "this is a static string";
  401568:       d28002e0        mov     x0, #0x17                       // #23
  40156c:       f90017a0        str     x0, [x29, #40]
  401570:       90000000        adrp    x0, 401000 <_init-0x2c0>
  401574:       913ee000        add     x0, x0, #0xfb8
  401578:       f9001ba0        str     x0, [x29, #48]
        std::string str = "this is a static string";
  40157c:       9100e3a0        add     x0, x29, #0x38
  401580:       94000062        bl      401708 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev>
}

 

#include<string>
#include<string_view>
using namespace std;
int main()
{
        //指针指向静态字符串
        const char* str_ptr = "this is a static string";

        //字符串数组
        char str_array[] = "this is a static string";
        //std::string
        std::string str = "this is a static string";
        //std::string_view
        std::string_view sv = "this is a static string";
}

 

 

当字符串数据的所有权已经确定(譬如由某个string对象持有),并且你只想访问(而不修改)他们时,使用 std::string_view 可以避免字符串数据的复制,从而提高程序效率,这(指程序效率)也是这篇文章的主要内容.

这次要介绍的 string_view 是 C++17 的一个主要特性.

 

 

 

我假设你已经了解了一些 std::string_view 的知识,如果没有,可以看看我之前的这篇文章.C++ 中的 string 类型在堆上存放自己的字符串数据,所以当你处理 string 类型的时候,很容易就会产生(堆)内存分配.

 

Small string optimisation

我们先看下以下的示例代码:

 1 #include <iostream>
 2 #include <string>
 3 
 4 void* operator new(std::size_t count) 
 5 {
 6     std::cout << "   " << count << " bytes" << std::endl;
 7     return malloc(count);
 8 }
 9 
10 void getString(const std::string& str) {}
11 
12 int main()
13 {
14     std::cout << std::endl;
15 
16     std::cout << "std::string" << std::endl;
17 
18     std::string small = "0123456789";
19     std::string substr = small.substr(5);
20     std::cout << "   " << substr << std::endl;
21 
22     std::cout << std::endl;
23 
24     std::cout << "getString" << std::endl;
25 
26     getString(small);
27     getString("0123456789");
28     const char message[] = "0123456789";
29     getString(message);
30 
31     std::cout << std::endl;
32     
33     return 0;
34 }

代码第4到第8行,我重载了全局的 new 操作符,这样我就能跟踪(堆)内存的分配了,而后,代码分别在第18行,第19行,第27行,第29行创建了string对象,所以这几处代码都会产生(堆)内存分配.相关的程序输出如下:

 

root@cloud:~/c++# ./srV1 

std::string
   56789

getString

root@cloud:~/c++# 

咦, 程序竟然没有产生内存分配?这是怎么回事?其实 string 类型只有在字符串超过指定大小(具体实现相关)时才会申请(堆)内存,对于 MSVC 来说,指定大小为 15, 对于 GCC 和 Clang,这个值则为 23.

这也就意味着,较短的字符串数据是直接存储于 string 的对象内存中的,不需要分配(堆)内存.

从现在开始,示例代码中的字符串将拥有至少30个字符,这样我们就不需要关注短字符串优化了.好了,带着这个前提(字符串长度>=30个字符),让我们重新开始讲解.

 

 

#include <iostream>
#include <string>

void* operator new(std::size_t count)
{
        std::cout << "   " << count << " bytes" << std::endl;
        return malloc(count);
}

void getString(const std::string& str) {}

int main()
{
        std::cout << std::endl;

        std::cout << "std::string" << std::endl;

        std::string small = "0123456789#0123456789#0123456789#0123456789#0123456789";
        std::string substr = small.substr(5);
        std::cout << "   " << substr << std::endl;

        std::cout << std::endl;

        std::cout << "getString" << std::endl;

        getString(small);
        getString("0123456789");
        const char message[] = "0123456789";
        getString(message);

        std::cout << std::endl;

        return 0;
}

 

 

root@cloud:~/c++# ./srV1 

std::string
   55 bytes
   50 bytes
   56789#0123456789#0123456789#0123456789#0123456789

getString

 

 

#include <iostream>
#include <string>

void* operator new(std::size_t count)
{
        std::cout << "   " << count << " bytes" << std::endl;
        return malloc(count);
}

void getString(const std::string& str) {}

int main()
{
        std::cout << std::endl;

        std::cout << "std::string" << std::endl;

        std::string small = "0123456789#0123456789#0123456789#0123456789#0123456789";
        getString(small);
        getString("01234567890123456789#0123456789#0123456789#0123456789#0123456789");
        const char message[] = "01234567890123456789#0123456789#0123456789#0123456789#0123456789$$$$$$$$$$$$$";
        getString(message);

        std::cout << std::endl;

        return 0;
}

 

 

root@cloud:~/c++# g++ -std=c++17 -g strV1.cpp -o   srV1
root@cloud:~/c++# ./srV1 

std::string
   55 bytes
   65 bytes
   78 bytes

root@cloud:~/c++#

 

 

#include <iostream>
#include <string>
#include <string_view>

void* operator new(std::size_t count)
{
        std::cout << "   " << count << " bytes" << std::endl;
        return malloc(count);
}

void getString(const std::string& str) {}

int main()
{
        std::cout << std::endl;

        std::cout << "std::string" << std::endl;

        std::string large= "0123456789#0123456789#0123456789#0123456789#0123456789";

        std::string_view largeStringView{ large.c_str(), large.size() };
        std::cout << std::endl;

        return 0;
}

 

root@cloud:~/c++# g++ -std=c++17 -g strV1.cpp -o   srV1
root@cloud:~/c++# ./srV1 

std::string
   55 bytes

 

No memory allocation required

现在, std::string_view 无需复制字符串数据的优点就更加明显了(std::string不进行短字符串优化的情况下),下面的代码就是例证.

 

 

 1 #include <cassert>
 2 #include <iostream>
 3 #include <string>
 4 #include <string_view>
 5 
 6 void* operator new(std::size_t count) 
 7 {
 8     std::cout << "   " << count << " bytes" << std::endl;
 9     return malloc(count);
10 }
11 
12 void getString(const std::string& str) {}
13 
14 void getStringView(std::string_view strView) {}
15 
16 int main()
17 {
18     std::cout << std::endl;
19 
20     std::cout << "std::string" << std::endl;
21 
22     std::string large = "0123456789-123456789-123456789-123456789";
23     std::string substr = large.substr(10);
24 
25     std::cout << std::endl;
26 
27     std::cout << "std::string_view" << std::endl;
28 
29     std::string_view largeStringView{ large.c_str(), large.size() };
30     largeStringView.remove_prefix(10);
31 
32     assert(substr == largeStringView);
33 
34     std::cout << std::endl;
35 
36     std::cout << "getString" << std::endl;
37 
38     getString(large);
39     getString("0123456789-123456789-123456789-123456789");
40     const char message[] = "0123456789-123456789-123456789-123456789";
41     getString(message);
42 
43     std::cout << std::endl;
44 
45     std::cout << "getStringView" << std::endl;
46 
47     getStringView(large);
48     getStringView("0123456789-123456789-123456789-123456789");
49     getStringView(message);
50 
51     std::cout << std::endl;
52     
53     return 0;
54 }

 

 

root@cloud:~/c++# mv controller.yaml  strV2.cpp
root@cloud:~/c++# g++ -std=c++17 -g strV2.cpp -o   srV2
root@cloud:~/c++# ./srV2

std::string
   41 bytes
   31 bytes

std::string_view

getString
   41 bytes
   41 bytes

getStringView

 

 

#include <iostream>
#include <string>
#include <string_view>
#include <cassert>

void* operator new(std::size_t count) 
{
        std::cout << "   " << count << " bytes" << std::endl;
        return malloc(count);
}

void getString(const std::string& str) {}

int main()
{
        std::cout << std::endl;

        std::cout << "std::string" << std::endl;

        std::string large= "0123456789#0123456789#0123456789#0123456789#0123456789";
        std::string substr = large.substr(10);
        std::cout << std::endl;
        std::cout << "std::string_view" << std::endl;

        std::string_view largeStringView{ large.c_str(), large.size() };
        largeStringView.remove_prefix(10);
        assert(substr == largeStringView);
        std::cout << substr << std::endl;
        std::cout << largeStringView << std::endl;

        std::cout << std::endl;

        std::cout << "getString" << std::endl;
        retu

 

 

root@cloud:~/c++# ./srV1 

std::string
   55 bytes
   45 bytes

std::string_view
#0123456789#0123456789#0123456789#0123456789
#0123456789#0123456789#0123456789#0123456789

 

 

#include <iostream>
#include <string>
#include <string_view>
#include <cassert>

void* operator new(std::size_t count)
{
        std::cout << "   " << count << " bytes" << std::endl;
        return malloc(count);
}

void getString(const std::string& str) {}
void getStringView(std::string_view strView) {}

int main()
{
        std::cout << std::endl;

        std::cout << "std::string" << std::endl;

        std::string large= "0123456789#0123456789#0123456789#0123456789#0123456789";
        std::cout << std::endl;
        std::cout << "std::string_view" << std::endl;

        std::string_view largeStringView{ large.c_str(), large.size() };
        std::cout << std::endl;
        std::cout << "getString" << std::endl;
        //getString(large);
        //getString("0123456789-123456789-123456789-123456789");
        const char message[] = "0123456789-123456789-123456789-123456789";
        //getString(message);
        std::cout << std::endl;
        std::cout << "getStringView" << std::endl;
        getStringView(large);
        getStringView("0123456789-123456789-123456789-123456789");
        getStringView(message);
        std::cout << std::endl;
        return 0;
}

 

 

root@cloud:~/c++# g++ -std=c++17 -g strV1.cpp -o   srV1
root@cloud:~/c++# ./srV1 

std::string
   55 bytes

std::string_view

getString

getStringView

 

 C++17,使用 string_view 来避免复制

使用std::string_view和tokenizer提升字符串处理性能

C++17剖析:string_view的实现,以及性能

gcc 5.2.0 手动更新(亲测)

 

posted on 2021-07-02 15:21  tycoon3  阅读(653)  评论(0编辑  收藏  举报

导航