为什么不允许从字符数组中初始化std::string? 在C++中,您可以从 char *和 const char */COD>初始化< STD::String < /Cord>对象,并且隐含地假定字符串将首先结束在指针之后找到的代码>代码> NUL< /Cord>字符。 然而,在C++字符串文字中,数组和模板构造函数可以用来获得正确的大小,即使字符串文字包含嵌入的代码> NUL例如,请参见以下玩具实现: #include <stdio.h> #include <string.h> #include <vector> #include <string> struct String { std::vector<char> data; int size() const { return data.size(); } template<typename T> String(const T s); // Hack: the array will also possibly contain an ending NUL // we don't want... template<int N> String(const char (&s)[N]) : data(s, s+N-(N>0 && s[N-1]=='\0')) {} // The non-const array removed as probably a lot of code // builds strings into char arrays and the convert them // implicitly to string objects. //template<int N> String(char (&s)[N]) : data(s, s+N) {} }; // (one tricky part is that you cannot just declare a constructor // accepting a `const char *` because that would win over the template // constructor... here I made that constructor a template too but I'm // no template programming guru and may be there are better ways). template<> String::String(const char *s) : data(s, s+strlen(s)) {} int main(int argc, const char *argv[]) { String s1 = "Hello\0world\n"; printf("Length s1 -> %i\n", s1.size()); const char *s2 = "Hello\0world\n"; printf("Length s2 -> %i\n", String(s2).size()); std::string s3 = "Hello\0world\n"; printf("std::string size = %i\n", int(s3.size())); return 0; } #包括 #包括 #包括 #包括 结构字符串{ std::矢量数据; int size()常量{return data.size();} 模板字符串(常量); //黑客:数组也可能包含一个结尾NUL //我们不想。。。 模板字符串(常量字符(&s)[N]) :数据(s,s+N-(N>0&&s[N-1]='\0')){ //非常量数组可能删除了大量代码 //将字符串构建到字符数组中,并将其转换 //隐式地连接到字符串对象。 //模板字符串(char&s)[N]):数据(s,s+N){ }; //(一个棘手的部分是,不能只声明构造函数 //接受“const char*”,因为这会赢得模板的支持 //构造器…这里我把构造器也做成了一个模板,但是我 //没有模板编程大师,可能有更好的方法)。 模板字符串::字符串(const char*s):数据(s,s+strlen(s)){} int main(int argc,const char*argv[]{ String s1=“Hello\0world\n”; printf(“长度s1->%i\n”,s1.size()); const char*s2=“你好\0world\n”; printf(“长度s2->%i\n”,字符串(s2.size()); std::string s3=“Hello\0world\n”; printf(“std::string size=%i\n”,int(s3.size()); 返回0; }
是否有任何特定的技术原因导致标准中没有考虑这种方法,而是使用嵌入的为什么不允许从字符数组中初始化std::string? 在C++中,您可以从 char *和 const char */COD>初始化< STD::String < /Cord>对象,并且隐含地假定字符串将首先结束在指针之后找到的代码>代码> NUL< /Cord>字符。 然而,在C++字符串文字中,数组和模板构造函数可以用来获得正确的大小,即使字符串文字包含嵌入的代码> NUL例如,请参见以下玩具实现: #include <stdio.h> #include <string.h> #include <vector> #include <string> struct String { std::vector<char> data; int size() const { return data.size(); } template<typename T> String(const T s); // Hack: the array will also possibly contain an ending NUL // we don't want... template<int N> String(const char (&s)[N]) : data(s, s+N-(N>0 && s[N-1]=='\0')) {} // The non-const array removed as probably a lot of code // builds strings into char arrays and the convert them // implicitly to string objects. //template<int N> String(char (&s)[N]) : data(s, s+N) {} }; // (one tricky part is that you cannot just declare a constructor // accepting a `const char *` because that would win over the template // constructor... here I made that constructor a template too but I'm // no template programming guru and may be there are better ways). template<> String::String(const char *s) : data(s, s+strlen(s)) {} int main(int argc, const char *argv[]) { String s1 = "Hello\0world\n"; printf("Length s1 -> %i\n", s1.size()); const char *s2 = "Hello\0world\n"; printf("Length s2 -> %i\n", String(s2).size()); std::string s3 = "Hello\0world\n"; printf("std::string size = %i\n", int(s3.size())); return 0; } #包括 #包括 #包括 #包括 结构字符串{ std::矢量数据; int size()常量{return data.size();} 模板字符串(常量); //黑客:数组也可能包含一个结尾NUL //我们不想。。。 模板字符串(常量字符(&s)[N]) :数据(s,s+N-(N>0&&s[N-1]='\0')){ //非常量数组可能删除了大量代码 //将字符串构建到字符数组中,并将其转换 //隐式地连接到字符串对象。 //模板字符串(char&s)[N]):数据(s,s+N){ }; //(一个棘手的部分是,不能只声明构造函数 //接受“const char*”,因为这会赢得模板的支持 //构造器…这里我把构造器也做成了一个模板,但是我 //没有模板编程大师,可能有更好的方法)。 模板字符串::字符串(const char*s):数据(s,s+strlen(s)){} int main(int argc,const char*argv[]{ String s1=“Hello\0world\n”; printf(“长度s1->%i\n”,s1.size()); const char*s2=“你好\0world\n”; printf(“长度s2->%i\n”,字符串(s2.size()); std::string s3=“Hello\0world\n”; printf(“std::string size=%i\n”,int(s3.size()); 返回0; },c++,arrays,string,string-literals,C++,Arrays,String,String Literals,是否有任何特定的技术原因导致标准中没有考虑这种方法,而是使用嵌入的NULs字符串文本初始化std::string对象时被截断?使用包含嵌入空字节的文本初始化std::string将起始指针和长度传递给构造函数 如果有一个专用的takes数组引用构造函数模板,那么这是最简单的,但是正如您所注意到的 这样一个只带有数组参数的模板将被认为是比只使用char const*的构造函数更糟糕的匹配,并且 目前尚不清楚是否应包含最终终止空值 第一点意味着物理代码接口将是一个单一的模板化构造函数,其中只有文
NUL
s字符串文本初始化std::string
对象时被截断?使用包含嵌入空字节的文本初始化std::string
将起始指针和长度传递给构造函数
如果有一个专用的takes数组引用构造函数模板,那么这是最简单的,但是正如您所注意到的
- 这样一个只带有数组参数的模板将被认为是比只使用
的构造函数更糟糕的匹配,并且char const*
- 目前尚不清楚是否应包含最终终止空值
char const data[] = "*.com\0*.exe\0*.bat\0*.cmd\0";
string s( data, data + sizeof( data ) ); // Including 2 nulls at end.
综上所述,当我定义自己的字符串类时,我包含了takes数组参数构造函数,但原因与方便性大不相同。也就是说,在文本的情况下,字符串对象可以简单地保持该指针,而无需复制,这不仅提供了效率,还为异常(例如异常)提供了安全性(正确性)。在C++11及更高版本中,const char
数组是最清晰的文本指示
但是,std::string
不能做到这一点:它不是为它设计的
如果经常这样做,则可以定义如下函数:
using Size = ptrdiff_t;
template< Size n >
auto string_from_data( char const (&data)[n] )
-> std::string
{ return std::string( data, data + n ); }
免责声明:编译器未接触或看到任何代码
[我第一次写这篇文章时就错过了,但有人提醒我。现在我要去喝咖啡了!] C++14字符串类型的文字切掉了最后的
\0
,因此使用这种文字,上面必须明确包含终止null值:
string const s = "*.com\0*.exe\0*.bat\0*.cmd\0\0"s;
除此之外,C++14字符串类型的文本似乎提供了所寻求的便利。C++14为字符串文本引入了后缀,使其成为
std::string
对象,因此主要用例不再相关
#include <iostream>
#include <string>
using namespace std;
using namespace std::literals;
int main() {
string foo = "Hello\0world\n";
string bar = "Hello\0world\n"s;
cout << foo.size() << " " << bar.size() << endl; // 5 12
cout << foo << endl; // Hello
cout << bar << endl; // Helloworld
return 0;
}
#包括
#包括
使用名称空间std;
使用名称空间std::literals;
int main(){
string foo=“Hello\0world\n”;
string bar=“Hello\0world\n”s;
首先,在char a[100]=“foo”;std::string s=a;
之后,s.length()
可能不应该是100。“当用于初始化std::string对象时,带有嵌入式NUL的字符串文字将被截断”--只有这样做了。可能是因为嵌入空字符的字符串是一种例外情况,可以用其他方法处理。@T.C.:好的观点…我实际上经常将字符串构建成数组,然后将它们转换成std::string
。删除了非常量版本…@Cheersandhth。-阿尔夫:我不确定你的意思…如何从一个包含嵌入的NUL
s的文本初始化std::string
对象?我错过了房间里的大象。当然没有人会喜欢字符串中的NUL
结尾。感谢大家记住了我忘记的东西。
#include <iostream>
#include <string>
using namespace std;
using namespace std::literals;
int main() {
string foo = "Hello\0world\n";
string bar = "Hello\0world\n"s;
cout << foo.size() << " " << bar.size() << endl; // 5 12
cout << foo << endl; // Hello
cout << bar << endl; // Helloworld
return 0;
}