Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.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
为什么不允许从字符数组中初始化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 - Fatal编程技术网 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" /> 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" />

为什么不允许从字符数组中初始化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*
    的构造函数更糟糕的匹配,并且

  • 目前尚不清楚是否应包含最终终止空值

第一点意味着物理代码接口将是一个单一的模板化构造函数,其中只有文档(而不是编辑器的工具提示)将讲述它接受或不接受的全部内容。一种修复方法是引入额外的虚拟解析器参数。这降低了便利性

第二点是引入bug的机会。构造函数最常用的用法无疑是普通字符串文本。然后,时不时地,它将用于嵌入空字节的文本和/或数组,但奇怪的是,最后一个字符被切掉了

相反,我们可以简单地命名值

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;
}