提问人:Fabian 提问时间:1/25/2017 最后编辑:songyuanyaoFabian 更新时间:9/19/2023 访问量:983
'string s(“hello”);' 和 'string s = “hello”;
Is there a difference between `string s("hello");` and `string s = "hello";` [duplicate]
问:
标题说明了一切。但是,请作为任何类的占位符。string
std::string s1("hello"); // construct from arguments
std::string s2 = "hello"; // ???
std::string s3; // construct with default values
s3 = "hello"; // assign
我想知道语句 for 是否与 for 或 for 相同。s2
s1
s3
答:
在本例中,并执行完全相同的操作:它们都调用构造函数 .(为了清楚起见,有些人更喜欢使用)。s1
s2
const char*
=
对于 ,调用默认构造函数,后跟 to 。s3
operator=
const char*
的情况是复制初始化。这是初始化,而不是像 那样分配。s2
s3
请注意,对于 ,效果与 和 相同,将调用 apporiate 构造函数(即 )来构造对象。但是复制初始化和直接初始化之间是有区别的(这种情况是 );对于复制初始化,将不考虑显式构造函数。假设 是声明的,这意味着不允许从 到 的隐式转换;那么第二个案例将不会再次编译。std::string
s1
s2
std::string::string(const char*)
s1
std::string::string(const char*)
explicit
const char*
std::string
复制初始化不如直接初始化宽松:显式构造函数不会转换构造函数,因此不考虑进行复制初始化。
如果一个类没有可访问的复制构造函数,则第二种初始化形式无效:
[temp]$ cat test.cpp
struct S {
S(int);
private:
S(const S&);
};
S s1(3); // okay
S s2 = 3; // invalid
[temp]$ clang++ -std=gnu++1z -c test.cpp
test.cpp:8:3: error: calling a private constructor of class 'S'
S s2 = 3; // invalid
^
test.cpp:4:5: note: declared private here
S(const S&);
^
1 error generated.
[temp]$
不同之处在于,第二个正式地创建一个 类型的临时对象,使用值 3 初始化,然后将该临时对象复制到 中。允许编译器跳过副本并直接构造,但前提是副本有效。S
s2
s2
评论
虽然所有 3 种方法的最终结果都是相同的(字符串将被分配给变量),但存在某些比语法更深层次的基本差异。我将介绍您的 3 个字符串涵盖的所有 3 个场景:
第一种情况:s1 是直接初始化的示例。直接初始化涵盖许多不同的方案,您的方案定义如下:
使用非空括号内的表达式列表进行初始化。
这里,s1 没有类数据类型,而是数据类型,因此将进行标准转换,将括号中的数据类型转换为 s1 的 cv 非限定版本,即 .Cv-unqualified 表示变量没有附加 (const) 或 (volatile) 等限定符。请注意,在直接初始化的情况下,它比 copy-initialization 要宽松得多,这是 s2 的主题。这是因为复制初始化将仅引用用户定义的non_explicit(即隐式)的构造函数和转换函数。另一方面,直接初始化考虑隐式和显式构造函数以及用户定义的转换函数。std::string
const *char
接下来,第二个字符串 s2 是复制初始化的示例。简单地说,它将值从左侧复制到右侧。这是一个示例:
当非引用类型 T 的命名变量(自动、静态或线程局部)声明时,初始值设定项由等号后跟表达式组成。
此方法涵盖的过程是相同的。由于 s2 没有类数据类型,而是数据类型,因此它将使用标准转换将右侧字符串的值转换为左侧的类型值。但是,如果函数是显式声明的,则无法像复制初始值设定项那样进行标准转换,并且代码的编译将失败。std::string
const *char
请参阅与 2 种初始化类型进行比较的一些代码示例。这应该可以消除上面的任何混淆:
struct Exp { explicit Exp(const char*) {} }; // This function has an explicit constructor; therefore, we cannot use a copy initialization here
Exp e1("abc"); // Direct initialization is valid here
Exp e2 = "abc"; // Error, copy-initialization does not consider explicit constructor
struct Imp { Imp(const char*) {} }; // Here we have an implicit constructor; therefore, a copy initializer can be used
Imp i1("abc"); // Direct initialization always works
Imp i2 = "abc"; // Copy initialization works here due to implicit copy constructor
转到第三种情况,它甚至不是初始化的情况,而是赋值的情况。就像您在评论中所说的那样,变量 s3 是用默认字符串初始化的。当您使用等号执行此操作时,该字符串将替换为“Hello”。这里发生的情况是,当 中声明 s3 时,将调用默认构造函数 ,并设置默认字符串值。当您使用 = 符号时,该默认字符串将在下一行中替换为 hello。string s3;
std::string
如果我们在跑步时看哪个在速度方面更有效,那么差异是微不足道的。但是,如果我们只这样做,s1 的运行时间最快:
int main(void)
{
string a("Hello");
}
这需要以下时间和内存来编译和运行:
编译时间: 0.32 秒, 绝对运行时间: 0.14 秒, CPU 时间: 0 秒, 内存峰值: 3 Mb, 绝对使用时间: 0,46 秒
如果我们看一下按以下方式编码的字符串 s2:
int main(void)
{
string a = "Hello";
}
然后程序运行所需的总时间为:
编译时间: 0.32 秒, 绝对运行时间: 0.14 秒, CPU 时间: 0 秒, 内存峰值: 3 Mb, 绝对使用时间: 0.47 秒
使用复制初始值设定项的运行时比直接初始值设定项多运行 0.01 秒。差异是存在的,但只是微不足道的。
第 3 种情况为 s3,如果按以下方式编码:
int main(void)
{
string a;
a = "Hello";
}
总运行、编译时间和空间占用:
编译时间: 0.32 秒, 绝对运行时间: 0.14 秒, CPU 时间: 0 秒, 内存峰值: 3 Mb, 绝对使用时间: 0.47 秒
我想在这里指出一点:第二种和第三种方法之间的运行时差异很可能不为零;相反,它是一个小于 0.01 秒的时间差,第 3 种方法需要更长的时间 (S3)。那是因为它有 2 行代码可以操作;一个是变量的声明,另一个是字符串对变量的赋值。
希望这能回答你的问题。
评论