Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在这种情况下,使用const char*或std::string更有效率的是什么_C++_Stdstring_String Literals_Storage Duration - Fatal编程技术网

C++ 在这种情况下,使用const char*或std::string更有效率的是什么

C++ 在这种情况下,使用const char*或std::string更有效率的是什么,c++,stdstring,string-literals,storage-duration,C++,Stdstring,String Literals,Storage Duration,我在应用程序中使用C和C++代码的组合。 我想通过使用三元运算符确定要打印的字符串,打印出布尔标志是真还是假,如下所示 如果我使用一个常量char*,编译器在程序启动之前是否很可能将这些字符串文本“Yes”和“No”存储在一些只读内存中 如果我使用std::string,当字符串超出范围时,它会被销毁吗?但是我想编译器仍然需要将字符串文本“Yes”和“No”存储在某个地方?我不确定 bool isSet = false; // More code //std::string isSetStr

我在应用程序中使用C和C++代码的组合。 我想通过使用三元运算符确定要打印的字符串,打印出布尔标志是真还是假,如下所示

如果我使用一个
常量char*
,编译器在程序启动之前是否很可能将这些字符串文本
“Yes”
“No”
存储在一些只读内存中

如果我使用
std::string
,当字符串超出范围时,它会被销毁吗?但是我想编译器仍然需要将字符串文本
“Yes”
“No”
存储在某个地方?我不确定

bool isSet = false;

// More code

//std::string isSetStr = isSet ? "Yes" : "No";
const char* isSetStr  =  isSet ? "Yes" : "No";

//printf ( "Flag is set ? : %s\n", isSetStr.c_str());
printf ( "Flag is set ? : %s\n", isSetStr);
你可以用它来测试。 前者(使用
const char*
)给出:

.LC0:
        .string "No"
.LC1:
        .string "Yes"
.LC2:
        .string "Flag is set ? : %s\n"
a(bool):
        test    dil, dil
        mov     eax, OFFSET FLAT:.LC0
        mov     esi, OFFSET FLAT:.LC1
        cmove   rsi, rax
        mov     edi, OFFSET FLAT:.LC2
        xor     eax, eax
        jmp     printf
.LC0:
        .string "Yes"
.LC1:
        .string "No"
.LC2:
        .string "Flag is set ? : %s\n"
a(bool):
        push    r12
        push    rbp
        mov     r12d, OFFSET FLAT:.LC1
        push    rbx
        mov     esi, OFFSET FLAT:.LC0
        sub     rsp, 32
        test    dil, dil
        lea     rax, [rsp+16]
        cmovne  r12, rsi
        or      rcx, -1
        mov     rdi, r12
        mov     QWORD PTR [rsp], rax
        xor     eax, eax
        repnz scasb
        not     rcx
        lea     rbx, [rcx-1]
        mov     rbp, rcx
        cmp     rbx, 15
        jbe     .L3
        mov     rdi, rcx
        call    operator new(unsigned long)
        mov     QWORD PTR [rsp+16], rbx
        mov     QWORD PTR [rsp], rax
.L3:
        cmp     rbx, 1
        mov     rax, QWORD PTR [rsp]
        jne     .L4
        mov     dl, BYTE PTR [r12]
        mov     BYTE PTR [rax], dl
        jmp     .L5
.L4:
        test    rbx, rbx
        je      .L5
        mov     rdi, rax
        mov     rsi, r12
        mov     rcx, rbx
        rep movsb
.L5:
        mov     rax, QWORD PTR [rsp]
        mov     QWORD PTR [rsp+8], rbx
        mov     edi, OFFSET FLAT:.LC2
        mov     BYTE PTR [rax-1+rbp], 0
        mov     rsi, QWORD PTR [rsp]
        xor     eax, eax
        call    printf
        mov     rdi, QWORD PTR [rsp]
        lea     rax, [rsp+16]
        cmp     rdi, rax
        je      .L6
        call    operator delete(void*)
        jmp     .L6
        mov     rdi, QWORD PTR [rsp]
        lea     rdx, [rsp+16]
        mov     rbx, rax
        cmp     rdi, rdx
        je      .L8
        call    operator delete(void*)
.L8:
        mov     rdi, rbx
        call    _Unwind_Resume
.L6:
        add     rsp, 32
        xor     eax, eax
        pop     rbx
        pop     rbp
        pop     r12
        ret
后者(使用std::string)给出了以下内容:

.LC0:
        .string "No"
.LC1:
        .string "Yes"
.LC2:
        .string "Flag is set ? : %s\n"
a(bool):
        test    dil, dil
        mov     eax, OFFSET FLAT:.LC0
        mov     esi, OFFSET FLAT:.LC1
        cmove   rsi, rax
        mov     edi, OFFSET FLAT:.LC2
        xor     eax, eax
        jmp     printf
.LC0:
        .string "Yes"
.LC1:
        .string "No"
.LC2:
        .string "Flag is set ? : %s\n"
a(bool):
        push    r12
        push    rbp
        mov     r12d, OFFSET FLAT:.LC1
        push    rbx
        mov     esi, OFFSET FLAT:.LC0
        sub     rsp, 32
        test    dil, dil
        lea     rax, [rsp+16]
        cmovne  r12, rsi
        or      rcx, -1
        mov     rdi, r12
        mov     QWORD PTR [rsp], rax
        xor     eax, eax
        repnz scasb
        not     rcx
        lea     rbx, [rcx-1]
        mov     rbp, rcx
        cmp     rbx, 15
        jbe     .L3
        mov     rdi, rcx
        call    operator new(unsigned long)
        mov     QWORD PTR [rsp+16], rbx
        mov     QWORD PTR [rsp], rax
.L3:
        cmp     rbx, 1
        mov     rax, QWORD PTR [rsp]
        jne     .L4
        mov     dl, BYTE PTR [r12]
        mov     BYTE PTR [rax], dl
        jmp     .L5
.L4:
        test    rbx, rbx
        je      .L5
        mov     rdi, rax
        mov     rsi, r12
        mov     rcx, rbx
        rep movsb
.L5:
        mov     rax, QWORD PTR [rsp]
        mov     QWORD PTR [rsp+8], rbx
        mov     edi, OFFSET FLAT:.LC2
        mov     BYTE PTR [rax-1+rbp], 0
        mov     rsi, QWORD PTR [rsp]
        xor     eax, eax
        call    printf
        mov     rdi, QWORD PTR [rsp]
        lea     rax, [rsp+16]
        cmp     rdi, rax
        je      .L6
        call    operator delete(void*)
        jmp     .L6
        mov     rdi, QWORD PTR [rsp]
        lea     rdx, [rsp+16]
        mov     rbx, rax
        cmp     rdi, rdx
        je      .L8
        call    operator delete(void*)
.L8:
        mov     rdi, rbx
        call    _Unwind_Resume
.L6:
        add     rsp, 32
        xor     eax, eax
        pop     rbx
        pop     rbp
        pop     r12
        ret
使用
std::string\u视图
,例如:

#include <stdio.h>
#include <string_view>


int a(bool isSet) {

// More code

std::string_view isSetStr = isSet ? "Yes" : "No";
//const char* isSetStr  =  isSet ? "Yes" : "No";

printf ( "Flag is set ? : %s\n", isSetStr.data());
//printf ( "Flag is set ? : %s\n", isSetStr);
}
总之,
constchar*
string\u视图
都给出了最佳的代码
string\u视图
const char*
要多输入一些代码。
std::string
是用来操作字符串内容的,所以这里的操作过于繁琐,导致代码效率低下

string\u视图
的另一个备注:它不保证字符串以NUL结尾。在本例中,它是,因为它是从以NUL结尾的静态字符串构建的。对于一般的
string_视图
使用
printf
,请使用
printf(“%s”、str.length()、str.data())

编辑:通过禁用异常处理,可以将
std::string
version减少为:

.LC0:
        .string "Yes"
.LC1:
        .string "No"
.LC2:
        .string "Flag is set ? : %s\n"
a(bool):
        push    r12
        mov     eax, OFFSET FLAT:.LC1
        push    rbp
        mov     ebp, OFFSET FLAT:.LC0
        push    rbx
        sub     rsp, 32
        test    dil, dil
        cmove   rbp, rax
        lea     r12, [rsp+16]
        mov     QWORD PTR [rsp], r12
        mov     rdi, rbp
        call    strlen
        mov     rsi, rbp
        mov     rdi, r12
        lea     rdx, [rbp+0+rax]
        mov     rbx, rax
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char const*, char const*)
        mov     rax, QWORD PTR [rsp]
        mov     QWORD PTR [rsp+8], rbx
        mov     edi, OFFSET FLAT:.LC2
        mov     BYTE PTR [rax+rbx], 0
        mov     rsi, QWORD PTR [rsp]
        xor     eax, eax
        call    printf
        mov     rdi, rsp
        call    std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose()
        add     rsp, 32
        pop     rbx
        pop     rbp
        pop     r12
        ret
.LC0:
.字符串“是”
.LC1:
.字符串“否”
.LC2:
.string“标志已设置?:%s\n”
a(布尔):
推送r12
mov eax,偏移平坦:.LC1
推动rbp
移动ebp,偏移平坦:.LC0
推送rbx
副区长,32
测试
cmove rbp,rax
lea r12,[rsp+16]
mov QWORD PTR[rsp],r12
移动rdi,rbp
打电话给斯特伦
移动rsi
mov-rdi,r12
lea rdx,[rbp+0+rax]
mov-rbx,rax
调用std::\uuucxx11::基本字符串::\u S\u复制\u字符(字符*,字符常量*,字符常量*)
mov rax,QWORD PTR[rsp]
mov QWORD PTR[rsp+8],rbx
移动edi,偏移平面:.LC2
mov字节PTR[rax+rbx],0
移动rsi,QWORD PTR[rsp]
异或eax,eax
调用printf
移动rdi,rsp
调用std::\uuuCXX11::基本字符串::\uM\uDispose()
加上rsp,32
流行音乐
流行限制性商业惯例
流行音乐r12
ret

这仍然比
字符串视图的版本多得多。请注意,编译器足够聪明,可以在这里删除堆上的内存分配,但它仍然被迫计算字符串的长度(即使printf也会自己计算它)。

任何一个版本都会在只读内存中分配字符串文本本身。这两个版本都使用了超出范围的局部变量,但字符串文本仍然存在,因为它们不是本地存储的

关于性能,C++容器类几乎总是比“原始”C效率低。在用G++O3测试代码时,我得到:

void test_cstr (bool isSet)
{
  const char* isSetStr  =  isSet ? "Yes" : "No";
  printf ( "Flag is set ? : %s\n", isSetStr);
}
拆卸(x86):

字符串文本被加载到只读位置,
isSetStr
变量被简单地优化掉

现在使用相同的编译器和选项(-O3)尝试此操作:

拆卸(x86):

字符串文本仍然分配在只读内存中,因此部分是相同的。但是我们得到了大量开销膨胀的代码


但另一方面,在本例中,到目前为止最大的瓶颈是控制台I/O,因此其余代码的性能甚至与此无关。努力编写尽可能可读的代码,并且只在实际需要时进行优化。C语言中的手动字符串处理速度很快,但也非常容易出错和麻烦。

字符串文字具有静态存储持续时间,它们在程序结束之前一直处于活动状态

请注意,如果在程序中使用相同的字符串文字,则编译器不必将该字符串文字存储为一个对象

就是这个表达

"Yes" == "Yes"
根据编译器选项,可以生成true或false。但通常默认情况下,相同的字符串文本存储为一个字符串文本

如果类型为
std::string
的对象未在命名空间中声明且没有关键字
static
,则该类型的对象具有自动存储持续时间。这意味着当控件传递给一个块时,这样的对象会被重新创建,并且在控件离开块时每次都被破坏。

< P>等效C++代码:

#include <string>

using namespace std::string_literals;

void test_cppstr (bool isSet)
{
  const std::string& isSetStr = isSet ? "Yes"s : "No"s;
  printf ( "Flag is set ? : %s\n", isSetStr.c_str());
}
冷静点

printf
将比嵌入程序源代码中的
const char[]
数据中的
std::string
的任何构造都要慢个数量级

检查代码性能时始终使用探查器。编写一个小程序来测试一个假设通常无法告诉你大程序中发生了什么。在您介绍的情况下,一个好的编译器将优化

int main(){printf ( "Flag is set ? : No\n");}
isSet的类型?“是”:“否”
const char*
,与将其存储在
std::string
const char*
(或
std::stringview
或…)中无关。(因此编译器对字符串文本的处理是平等的)

根据,

std::string
版本的速度慢了约6倍,这是可以理解的,因为它需要额外的动态分配


除非您需要额外的代码<代码> STD::String ,否则您可能会停留在<代码> const char */COS>。

也要考虑。而且是的,用于初始化指针的字符串、字符串或字符串视图将存储在执行文件中。
#include <string>

using namespace std::string_literals;

void test_cppstr (bool isSet)
{
  const std::string& isSetStr = isSet ? "Yes"s : "No"s;
  printf ( "Flag is set ? : %s\n", isSetStr.c_str());
}
#include <string>

using namespace std::string_literals;

const std::string yes("Yes");
const std::string no("No");

void test_cppstr (bool isSet)
{
  const std::string& isSetStr = isSet ? yes : no;
  printf ( "Flag is set ? : %s\n", isSetStr.c_str());
}
int main(){printf ( "Flag is set ? : No\n");}