C++ 字符串声明
Posted
技术标签:
【中文标题】C++ 字符串声明【英文标题】:C++ string declaration 【发布时间】:2011-11-09 17:35:00 【问题描述】:我从一开始就学习 C++,但我没有掌握整个字符串主题。
下面三个代码有什么区别?
std::string s = std::string("foo");
std::string s = new std::string("foo");
std::string s = "foo";
【问题讨论】:
注意一般要使用选项4:std::string s("foo");
@JerryCoffin:这与选项 3 有何不同?
@MikeSeymour:它直接初始化而不是复制初始化。至少在概念上,#3 创建一个从提供的常量初始化的临时字符串,然后使用复制构造函数从该值创建s
(尽管,诚然,编译器通常会忽略它,并执行相当于直接初始化的操作)。
不要忘记使用最新标准的统一初始化语法的变体,即std::string s"foo";
【参考方案1】:
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*
类型的指针分配给std::string
类型的s
。 std::string
类的设计阻止了这种情况的发生,因此编译失败。
C++ 不是 Java。这不是通常创建对象的方式,因为如果您忘记 delete
返回的 std::string
对象,您将泄漏内存。使用std::string
的主要好处之一是它会自动为您管理底层字符串缓冲区,所以new
-ing 它有点违背了这个目的。
std::string s = "foo";
这与#1 基本相同。它在技术上初始化一个包含“foo”的新临时字符串,然后将其分配给s
。同样,编译器通常会忽略临时变量(事实上,现在几乎所有非愚蠢的编译器实际上都会消除临时变量),因此实际上它只是在适当的位置构造了一个名为 s
的新对象。
具体来说,它调用std::string
中的转换构造函数,该构造函数接受const char*
参数。上述代码中,要求转换构造函数为非explicit
,否则编译错误。转换构造函数实际上是非explicit
为std::string
s,所以上面确实编译。
这就是std::string
s 通常的初始化方式。当s
超出范围时,s
对象将与底层字符串缓冲区一起被销毁。请注意,以下内容具有相同的效果(并且是另一种初始化 std::string
s 的典型方式),因为它还会生成一个名为 s
的对象,其中包含“foo”。
std::string s("foo");
但是,there's a subtle difference between std::string s = "foo";
and std::string s("foo");
,其中之一是在上述情况下转换构造函数可以是explicit
或非explicit
。
【讨论】:
+1 表示编译器不一定会在 #1 中创建临时文件。 请注意,就语言而言,#1 和 #3 是等价的。 那么std::string("foo")
在堆栈上创建“foo”,new std::string("foo")
在堆上创建 foo?
@Leif Ericson:是的。 (我称“堆”为“免费存储”。)
@LeifEricson:基本上是的。标准自娱自乐地谈到堆栈的“自动存储”和堆的“动态存储”......但我所知道的任何实现都没有利用不同的解释。【参考方案2】:
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
类包含一个接受const char *
的非explicit
构造函数。这允许编译器隐式构造一个临时的std::string
对象。之后语义与案例 1 相同。
【讨论】:
【参考方案3】:-
创建一个临时字符串对象并将值复制到
s
不编译,new std::string("foo")
返回一个指向一些新分配的内存的指针。
为此,您应该将 s 声明为指向字符串 std::string* s
的指针。
从 C 字符串构造字符串。
您应该在大多数(如果不是全部)情况下使用第三个选项。
【讨论】:
【参考方案4】:1会创建一个临时变量(右手边),然后调用赋值运算符将值赋给s
2 将在堆上创建一个std::string
的实例并返回一个指向它的指针,并且由于无法将指针分配给非指针类型而导致分配失败
3 将构建一个 std::string 并从 const char*
初始化它
【讨论】:
“您不能将指针分配给非指针类型”:您认为bool s; s = new std::string("Hello, world.");
是编译时错误吗?顺便说一句,等号不是赋值(例如,即使 Foo::operator=(int)
是私有的,写 Foo x = 12;
也是合法的)。
@6502:他的措辞是错误的,但无论哪种方式都不能从std::string
分配
@MooingDuck:这个答案在几点上是错误的:A)那些不是赋值,是初始化(在 C++ 中,这是另一回事,具有不同的规则和语义,答案的赋值运算符会说话about in 1 是 NOT 调用的),B)短语“您不能将指针分配给非指针类型”只是错误的......您可以从 a 分配(并初始化)一个布尔值指针。第 2 点的 IMO 措辞非常糟糕,因为它看起来像是在说代码会编译并且会出现运行时错误……但至少有人怀疑这不是 Fred 的意思。【参考方案5】:
在数字 1 上,您正在使用构造函数创建一个临时字符串,然后将其分配给 s。 2 号甚至没有编译。 在数字 3 上,您正在创建一个新字符串,然后为其分配一个值。
【讨论】:
以上是关于C++ 字符串声明的主要内容,如果未能解决你的问题,请参考以下文章