hyd*_*yde 22 c++ null stdstring
我相信,std::string从NULL char指针初始化是未定义的行为.所以,这里是构造函数的替代版本,其中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
}
Run Code Online (Sandbox Code Playgroud)
编辑,构造函数声明里面class MyClass:
MyClass(const char *cstr = NULL);
Run Code Online (Sandbox Code Playgroud)
其中哪一个,或者可能是其他东西,是std::string从可能NULL指针初始化的最佳或最正确的方法,为什么?不同的C++标准有什么不同?假设正常发布构建优化标志.
我正在寻找一个答案,解释为什么一种方式是正确的方式,或一个带有参考链接的答案(这也适用于答案是"无关紧要"),而不仅仅是个人意见(但如果你必须,至少让它只是一个评论).
Ker*_* SB 20
最后一个是愚蠢的,因为它可以使用初始化.
前两个在语义上完全相同(想想c_str()成员函数),所以更喜欢第一个版本,因为它是最直接和最惯用的,也是最容易阅读的.
(这里将是一个语义的区别,如果std::string有一个constexpr默认的构造函数,但它不会.不过,这是有可能的是std::string()来自不同的std::string(""),但我不知道这样做的任何实现,因为似乎使很多不另一方面,流行的小字符串优化现在意味着两个版本可能都不会执行任何动态分配.)
更新:正如@Jonathan指出的那样,两个字符串构造函数可能会执行不同的代码,如果这对您很重要(尽管它确实不应该),您可能会考虑第四个版本:
: cstr ? cstr : std::string()
Run Code Online (Sandbox Code Playgroud)
可读和默认构造.
第二次更新:但更喜欢cstr ? cstr : "".如下所示,当两个分支调用相同的构造函数时,可以使用条件移动和无分支非常有效地实现.(所以这两个版本确实生成了不同的代码,但第一个版本更好.)
对于咯咯笑,我已经通过Clang 3.3运行了两个版本-O3,在x86_64上运行了struct 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
Run Code Online (Sandbox Code Playgroud)
空字符串构造函数(""):
.cfi_offset r14, -16
mov 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
Run Code Online (Sandbox Code Playgroud)
在我的情况下,它甚至会""产生更好的代码:两个版本都调用strlen,但是空字符串版本不使用任何跳转,只使用条件移动(因为调用相同的构造函数,只有两个不同的参数).当然,这是一个完全没有意义,不可移植和不可转移的观察,但它只是表明编译器并不总是需要你想象的那么多帮助.只需编写看起来最好的代码.
首先,你是对的,来自http://www.cplusplus.com/reference/string/string/string/:
如果 s 是空指针,如果 n == npos,或者如果 [first,last) 指定的范围无效,则会导致未定义的行为。
此外,这取决于 NULL 指针对您意味着什么。我假设它与您的空字符串相同。
我会选择第一个,因为它是我读得最好的一个。第一个解决方案和第二个是相同的。如果您的字符串是const.