C-Style字符串到std :: string转换澄清

时间:2012-04-11 15:44:25

标签: c++ string copy

我有几个问题,我认为对于有C ++经验的人来说很容易回答,我会大胆提出TL的问题; DR

给出以下代码:

void stringTest(const std::string &s)
{
    std::cout << s << std::endl;
}

int main()
{
    stringTest("HelloWorld");
}

希望有人可以在我的思考过程中指出错误:

为什么在传递C样式字符串时,stringTest中的参数必须标记为const?是否存在使用其cstyle字符串构造函数的std :: string的隐式转换因此,“s”不再是对文字的引用(并且不需要是const)。

此外,cstyle字符串构造函数看起来是什么样的,编译器如何知道在看到时调用它:

stringTest("HelloWorld");

它是否只是将字符串文字识别为char *?

在研究复制构造函数时,我偶然发现了这些问题。我自己澄清的另一个快速问题......

在类似的情况下:

std::string s = "HelloWorld";

cstyle字符串构造函数是否用于实例化临时std :: string,然后使用字符串复制构造函数将临时字符串复制到“s”中?

std::string(const std::string&);

4 个答案:

答案 0 :(得分:2)

  

为什么在传递C-Style字符串时,stringTest中的参数必须标记为const?

只有在参数是引用时才需要,因为临时std::string是从您传入的char const*构建的,而非const引用临时是非法的。

  

它是否只是将字符串文字识别为char *?

字符串文字是char const数组,它会衰减到char const*。由此,编译器推断它应该使用非explicit构造函数std::string::string(char const *)来构造临时。

  

cstyle构造函数是否用于实例化临时std :: string,然后使用字符串复制构造函数将临时字符串复制到“s”中?

比这复杂一点。是的,创建了一个临时的。但复制构造函数可能会被调用,也可能不会被调用;允许编译器跳过复制结构作为优化。但是仍然必须提供复制构造函数,因此以下内容将无法编译:

class String {
    String(char const *) {}
  private:
    String(String const &);
};

int main()
{
    String s = "";
}

此外,在C ++ 11中,将使用移动构造函数(如果提供);在这种情况下,不需要复制构造函数。

答案 1 :(得分:2)

  

为什么在传递C-Style字符串时,stringTest中的参数必须标记为const?

编辑: 临时工必须是不变的。见larsmans评论和回答,他是对的。

简单的理由:

void change(std::string& c) { c = "abc"; }
change("test"); // what should the code exactly do??
  

此外,cstyle字符串构造函数看起来是什么样的,编译器如何知道在看到它时调用它:

它为std::string构造函数

查找string(char*)
  

在类似的情况下:

std::string s = "HelloWorld";
     

cstyle构造函数是否用于实例化临时std :: string,然后使用字符串复制构造函数将临时字符串复制到“s”中?:   std :: string(const std :: string&amp;);

没有。在这个确切的情况下(TYPE variable = SOMETHING),它与写TYPE variable(SOMETHING);相同。因此,不使用复制。

答案 2 :(得分:2)

  

它是否只是将字符串文字识别为类似于   字符*?

原始问题的这一部分没有像我所希望的那样清楚地回答。尽管如此,我还是完全赞同(和投票通过)Yossarian对其余部分的回答。

基本上,当您在代码中看到字符串文字时,您需要了解编译器正在做什么。那个字符数组(就像任何c风格的字符串一样)实际上存储在一个完全不同的位置,而不是它所属的代码(取决于体系结构,数字文字可以存储在位置本身作为程序集的一部分/二进制指令)。这里的两个代码块“或多或少”等效(忽略缺少包含或名称空间声明):

int main(void)
{
    cout << "Hello!" << endl;
    return 0;
}

这更接近于“真正”发生的事情:

const char HELLO_STR[] = { 'H', 'e', 'l', 'l', 'o', '!', 0 };

int main(void)
{
    cout << HELLO_STR << endl;
    return 0;
}

请原谅我,如果我在数组init或其他方面犯了错误,但我认为这表达了我的意思,就是字符串文字“真正”存储的位置。它不是内联的,但对于定义它的程序的另一部分来说是一个不可见的常量。另外,一些(大多数?)编译器还将字符串文字“排列在一起”,这样如果你在50个地方使用相同的文字,它只存储其中一个,并且所有这些都引用回相同的常量,节省记忆。

所以请记住,无论何时使用字符串文字,你都会使用一个存在于“隐形”某处的const char [N],它被隐式转换为const char *。

答案 3 :(得分:0)

在此示例中,const string & s需要从参数“HelloWorld”调用构造函数。使用的构造函数是类型转换构造。

string& s不会这样做,因为s直接引用字符串对象。

类型转换由类似于

的内容定义
 basic_string(const _CharT* __s);

使用typedef

typedef basic_string<char>    string; 

因此声明将评估为

basic_string(const char * __s)