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 类型的sstd::string 类的设计阻止了这种情况的发生,因此编译失败。

C++ 不是 Java。这不是通常创建对象的方式,因为如果您忘记 delete 返回的 std::string 对象,您将泄漏内存。使用std::string 的主要好处之一是它会自动为您管理底层字符串缓冲区,所以new-ing 它有点违背了这个目的。

std::string s = "foo";

这与#1 基本相同。它在技术上初始化一个包含“foo”的新临时字符串,然后将其分配给s。同样,编译器通常会忽略临时变量(事实上,现在几乎所有非愚蠢的编译器实际上都会消除临时变量),因此实际上它只是在适当的位置构造了一个名为 s 的新对象。

具体来说,它调用std::string 中的转换构造函数,该构造函数接受const char* 参数。上述代码中,要求转换构造函数为非explicit,否则编译错误。转换构造函数实际上是非explicitstd::strings,所以上面确实编译。

这就是std::strings 通常的初始化方式。当s 超出范围时,s 对象将与底层字符串缓冲区一起被销毁。请注意,以下内容具有相同的效果(并且是另一种初始化 std::strings 的典型方式),因为它还会生成一个名为 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++ 字符串声明的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中方便地声明编译时字符串

字符串未在此范围内声明 C++

C++:声明一个在头文件中返回字符串的函数?

如何在 C++ 中声明一个字符串数组?

不可能在 C++ 中声明字符串类型

如何在 C++ 中声明一个字符串而不赋值?