5

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

给定以下代码:

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

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

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

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

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

stringTest("HelloWorld");

它是否只是将字符串文字识别为 char* 之类的东西?

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

在类似的情况下:

std::string s = "HelloWorld";

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

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

4 回答 4

2

为什么 stringTest 中的参数在传递 C-Style 字符串时必须标记为 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 中,将使用移动构造函数(如果提供);在这种情况下,不需要复制构造函数。

于 2012-04-11T15:47:52.853 回答
2

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

编辑:临时变量必须是不可变的。看到拉尔斯曼的评论和回答,他是对的。

原因很简单:

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&);

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

于 2012-04-11T15:50:29.350 回答
2

它是否只是将字符串文字识别为 char* 之类的东西?

原始问题的这一部分没有像我希望的那样清楚地回答。不过,我完全赞同(并投票赞成)约塞连对其余部分的回答。

基本上,您需要了解编译器在看到代码中的字符串文字时在做什么。该字符数组(实际上是任何 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;
}

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

所以请记住,每当您使用字符串文字时,您都在使用“隐形”存在于某处的 const char[N],它被隐式转换为 const char*。

于 2012-04-11T16:02:22.807 回答
0

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

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

类型转换由类似于

 basic_string(const _CharT* __s);

使用 typedef

typedef basic_string<char>    string; 

所以声明将评估为

basic_string(const char * __s)    
于 2012-04-11T15:49:17.493 回答