在我阅读nVidia CUDA源代码时,我偶然发现了这两行:
std::string stdDevString;
stdDevString = std::string(device_string);
请注意,device_string是char [1024]。问题是:为什么要构造一个空的std :: string,然后用C字符串作为参数再次构造它?他们为什么不在一行中拨打std::string stdDevString = std::string(device_string);
?
是否存在此代码试图逃避/使用的隐藏字符串初始化行为?是确保stdDevString里面的C字符串无论什么都保持null终止?因为据我所知,将std :: string初始化为非空终止的C字符串仍会出现问题。
答案 0 :(得分:4)
他们为什么不在一行中拨打
std::string stdDevString = std::string(device_string);
?
他们所做的没有充分的理由。给定std::string::string(const char*)
构造函数,您只需使用以下任何一个:
std::string stdDevString = device_string;
std::string stdDevString(device_string);
std::string stdDevString{device_string}; // C++11 { } syntax
两步默认构造然后分配只是(坏)程序员风格或疏忽。没有优化,它确实做了一些不必要的构造,但这仍然相当便宜。它可能会被优化删除。不是一个大问题 - 我怀疑我是否愿意在代码审查中提及它,除非它处于极其敏感的区域,但是最好推迟声明变量,直到有用的初始值可用于构建它们,将其本地化所有在一个地方:不仅容易出错,而且交叉引用,但它最大限度地减少了变量的范围,简化了其使用的推理。
是否确保
stdDevString
内的C字符串无论什么都保持空终止?
不 - 这没有任何区别。从C ++ 11开始,无论使用哪个构造函数,stdDevString
中的内部缓冲区都将保持NUL终止,而对于C ++ 03并不一定终止 - 请参阅下面的C ++ 03详细专用标题 - 但无论结构/作业如何完成,都无法保证。
因为据我所知,将
std::string
初始化为非空终止的C字符串仍会出现问题。
你说得对 - 你列出的任何构造选项都只会将ASCIIZ文本复制到std::string
- 考虑到第一个NUL('\0'
)终结符。如果char数组不是NUL终止的,那么就会出现问题。
(这是一个单独的问题,std::string
内的缓冲区是否保持NUL终止 - 上面讨论过。
请注意,有一个单独的string(const char*, size_type)
构造函数, 可以 创建具有嵌入式NUL的字符串,并且不会尝试进一步阅读(构造函数(4) )here)
无论构建和初始化std::string
的哪种方式, 在C ++ 11之前 ,标准都不要求它在字符串的缓冲区内以NUL结尾。 std::string
最好被想象为包含一堆可能不可打印(松散地说,ftp /文件I / O意义上的二进制)字符,从地址data()
开始并扩展为size()
个字符。所以,如果你有:
std::string x("help");
x[4]; // undefined behaviour: only [0]..[3] are safe
x.at(4); // will throw rather than return '\0'
x.data()[4]; // undefined behaviour, equivalent to x[4] above
x.c_str()[4]; // safely returns '\0', (perhaps because a NUL was always
// at x[4], one was just added, or a new NUL-terminated
// buffer was just prepared - in which case data() may
// or may not start returning it too)
请注意,std :: string API需要c_str()
才能返回指向NUL终止值的指针。为此,它可以:
NUL
(在这种情况下,data[5]
将会发生以确保该实现的安全性,但代码如果实现更改或代码移植到另一个标准库实现等,则可能会中断。)反应等到调用c_str()
,然后:
data()
),请追加NUL
并返回data()
将返回的相同指针值< / LI>
NUL
终止它,并返回指向它的指针(通常是但是可选地这个缓冲区将替换旧的缓冲区,将被删除,以便之后立即调用data()
将返回c_str()
返回的相同指针答案 1 :(得分:1)
我会说它相当于写作:
std::string stdDevString = std::string(device_string);
或者,甚至更简单:
std::string stdDevString = device_string;
创建std :: string后,它包含C字符串中数据的私有副本。
答案 2 :(得分:1)
我认为将此视为不良编码是无知的。如果我们假设这个字符串是在文件范围或静态变量中分配的,那么它可能是良好的编码。
当为具有非易失性存储器的嵌入式系统编程C ++时,有许多原因可以避免静态初始化:主要原因是它在程序开头添加了大量开销代码,其中所有这些变量都是很多被初始化。如果它们是类的实例,则将调用构造函数。
这将导致程序执行开始时的延迟峰值。您不希望此工作负载达到峰值,因为在启动程序时还有许多重要的任务要做,例如设置各种硬件。
为了避免这种情况,通常在编译器中启用一个选项来删除这样的静态初始化,然后以不初始化静态/全局变量的方式编写代码,而是在运行时设置它们。
在这样的系统上,OP发布的代码是正确的方法。
答案 3 :(得分:0)
对我来说看起来像是一件艺术品。也许之间还有一些其他的代码,然后它被删除了,有人懒得将这两行剩余的行加入到一个单独的代码中。