我从一开始就学习C ++而且我没有得到整个字符串主题。
以下三个代码之间有什么区别?
std::string s = std::string("foo");
std::string s = new std::string("foo");
std::string s = "foo";
答案 0 :(得分:42)
std::string s = std::string("foo");
这将创建一个包含“foo”的临时std::string
对象,然后将其分配给s
。 (请注意,编译器可能会忽略临时。在这种情况下,临时elison是C ++标准明确允许的。)
std::string s = new std::string("foo");
这是一个编译器错误。表达式new std::string("foo")
在免费商店上创建std::string
,并返回指向std::string
的指针。然后,它尝试将类型为std::string*
的返回指针分配给s
类型的std::string
。 std::string
类的设计可防止这种情况发生,因此编译失败。
C ++不是Java。这不是通常创建对象的方式,因为如果忘记delete
返回的std::string
对象,则会泄漏内存。使用std::string
的一个主要好处是它会自动为您管理基础字符串缓冲区,因此new
使它失败了。
std::string s = "foo";
这与#1基本相同。它在技术上初始化一个包含“foo”的新临时字符串,然后将其分配给s
。同样,编译器通常会忽略临时(实际上几乎所有非愚蠢的编译器实际上都消除了临时),因此在实践中它只是构建了一个名为s
的新对象。
具体来说,它在std::string
中调用一个接受const char*
参数的转换构造函数。在上面的代码中,转换构造函数必须是非explicit
,否则它是编译器错误。转换构造函数实际上是explicit
的非std::string
,所以上面的编译。
这是std::string
通常初始化的方式。当s
超出范围时,s
对象将与底层字符串缓冲区一起被销毁。请注意,以下内容具有相同的效果(并且是另一种典型的std::string
初始化方式),因为它还会生成一个名为s
的对象,其中包含“foo”。
std::string s("foo");
但是,there's a subtle difference between std::string s = "foo";
and std::string s("foo");
,其中之一就是转换构造函数在上述情况下可以是explicit
或非explicit
。
答案 1 :(得分:3)
std::string s = std::string("foo");
这称为复制初始化。它在功能上与直接初始化相同
std::string s( "foo" );
但前者确实要求复制构造函数可用,编译器可能会创建一个临时对象,但大部分都会忽略临时对象并直接构造s
以包含"foo"
。
std::string s = new std::string("foo");
这将无法编译,因为new
返回一个指针。要使其有效,您需要s
的类型为std::string *
。然后该行动态分配std::string
对象并将指针存储在s
中。一旦你完成使用它,你需要delete
。
std::string s = "foo";
这与第一次几乎相同。它是复制初始化,但它有一个附加的约束。它要求std::string
类包含一个非explicit
构造函数,该构造函数需要const char *
。这允许编译器隐式构造临时std::string
对象。之后,语义与案例1完全相同。
答案 2 :(得分:2)
s
new std::string("foo")
返回指向一些新分配的内存的指针。
为此,您应该将s声明为指向字符串std::string* s
的指针。你应该在大多数情况下使用第三个选项 - 如果不是全部的话。
答案 3 :(得分:2)
1将创建一个临时变量(右侧),然后调用赋值运算符将值赋给s
2将在堆上创建std::string
的实例并返回指向它的指针,并且在分配中将失败,因为您无法将指针指定给非指针类型
3将构建一个std :: string并从const char*
答案 4 :(得分:1)
在数字1上,您将使用构造函数创建临时字符串,然后将其分配给s。 2号甚至没有编译。 在数字3上,您将创建一个新字符串,然后为其指定一个值。