c – 从可能的NULL char指针初始化std :: string

前端之家收集整理的这篇文章主要介绍了c – 从可能的NULL char指针初始化std :: string前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
从NULL char指针初始化std :: string是未定义的行为,我相信.所以,这里是构造函数的替代版本,其中mStdString是一个类型为std :: string的成员变量:
void MyClass::MyClass(const char *cstr) :
    mStdString( cstr ? cstr : "")
{}

void MyClass::MyClass(const char *cstr) :
    mStdString(cstr ? std::string(cstr) : std::string())
{}

void MyClass::MyClass(const char *cstr)
{
    if (cstr) mStdString = cstr;
    // else keep default-constructed mStdString
}

编辑,类MyClass中的构造函数声明:

MyClass(const char *cstr = NULL);

这些或其他可能的其中一个是从可能的NULL指针初始化std :: string的最佳或最适当的方式,为什么?不同的C标准是不同的?假设正常的版本构建优化标志.

我正在寻找一个答案,解释为什么一种方式是正确的方式,或一个答案与参考链接(这也适用,如果答案是“无关紧要”),而不仅仅是个人意见(但如果你必须,至少让它只是一个评论).

解决方法

最后一个是愚蠢的,因为它可以不使用初始化.

前两个在语义上完全相同(想到c_str()成员函数),所以更喜欢第一个版本,因为它是最直接和惯用的,最容易阅读.

(如果std :: string有一个constexpr的默认构造函数,会有一个语义上的差异,但是std :: string()与std :: string(“”)不同,但是我可以不知道这样做的任何实现,因为它似乎没有什么意义,另一方面,流行的小字符串优化现在意味着这两个版本可能不会执行任何动态分配.)

更新:正如@Jonathan指出的那样,两个字符串构造函数可能会执行不同的代码,如果这对你很重要(尽管不是这样),你可能会考虑第四个版本:

: cstr ? cstr : std::string()

可读和默认构造.

第二次更新:但更喜欢cstr? cstr:“”.如下所示,当两个分支都调用相同的构造函数时,可以非常有效地使用条件移动和无分支来实现. (所以这两个版本确实产生不同的代码,但是第一个更好)

对于giggles,我已经运行两个版本通过Clang 3.3,与-O3,在x86_64,一个结构foo;像你的和一个函数foo bar(char const * p){return p; }:

默认构造函数(std :: string()):

.cfi_offset r14,-16
    mov     R14,RSI
    mov     RBX,RDI
    test    R14,R14
    je      .LBB0_2
    mov     RDI,R14
    call    strlen
    mov     RDI,RBX
    mov     RSI,R14
    mov     RDX,RAX
    call    _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm
    jmp     .LBB0_3
.LBB0_2:
    xorps   XMM0,XMM0
    movups  XMMWORD PTR [RBX],XMM0
    mov     QWORD PTR [RBX + 16],0
.LBB0_3:
    mov     RAX,RBX
    add     RSP,8
    pop     RBX
    pop     R14
    ret

空字符串构造函数(“”):

.cfi_offset r14,RDI
    mov     EBX,.L.str
    test    RSI,RSI
    cmovne  RBX,RSI
    mov     RDI,RBX
    call    strlen
    mov     RDI,R14
    mov     RSI,RBX
    mov     RDX,RAX
    call    _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcm
    mov     RAX,R14
    add     RSP,8
    pop     RBX
    pop     R14
    ret

.L.str:
    .zero    1
    .size    .L.str,1

在我的情况下,甚至会出现“”生成更好的代码:两个版本调用strlen,但空字符串版本不使用任何跳转,只有条件移动(因为调用相同的构造函数,只有两个不同的参数) .当然,这是一个完全无意义的,不可移植的和不可转移的观察,但它只是表明编译器并不总是需要像你想象的那样多的帮助.只需编写看起来最好的代码.

猜你在找的C&C++相关文章