`string s(“hello”);`和`string s =“hello”;`之间有区别吗?

时间:2017-01-25 08:03:59

标签: c++ initialization variable-assignment copy-constructor assignment-operator

标题说明了一切。但是,请将string作为任何课程的占位符。

std::string s1("hello");  // construct from arguments
std::string s2 = "hello"; // ???
std::string s3;           // construct with default values
s3 = "hello";             // assign

我想知道s2的陈述是否与s1s3的陈述相同。

4 个答案:

答案 0 :(得分:14)

s2的情况为copy initialization。这是初始化,而不是s3的情况。

请注意,对于std::strings1s2的效果相同,将调用apporiate构造函数(即std::string::string(const char*))来构造对象。但是复制初始化与direct initializations1的情况)之间存在差异;对于复制初始化,不会考虑显式构造函数。假设std::string::string(const char*)被声明为explicit,这意味着不允许从const char*std::string的隐式转换;然后第二种情况不会再次编译。

  

复制初始化比直接初始化更不宽容:显式构造函数不转换构造函数,不考虑复制初始化。

答案 1 :(得分:2)

在这种情况下,s1s2完全 同样的事情:他们都将构造函数调用到const char*。 (为了清楚起见,有些人更喜欢使用=

对于s3,调用默认构造函数,然后调用operator=const char*

答案 2 :(得分:2)

虽然所有3种方法的最终结果是相同的(字符串将分配给变量),但是某些基本的差异比语法更深入。我将回顾您的3个字符串所涵盖的所有3种情况:

第一种情况:s1是直接初始化的一个例子。直接初始化涵盖了许多不同的场景,您的定义如下:

  

使用非空的括号表达式列表进行初始化。

这里,s1没有类数据类型而是std::string数据类型,因此将进行标准转换以将括号中的数据类型转换为sv的非限定版本s1,即{ {1}}。 Cv-unqualified意味着没有限定符,例如(const)(volatile)附加到变量。请注意,在直接初始化的情况下,它比复制初始化更宽松,复制初始化是s2的主题。这是因为复制初始化仅引用用户定义的非显式(即隐式)的构造函数和转换函数。另一方面,直接初始化考虑隐式和显式构造函数以及用户定义的转换函数。

继续,第二个字符串s2是复制初始化的一个例子。简单地说,它将值从左侧复制到右侧。这是一个例子:

  

当声明非引用类型T的命名变量(自动,静态或线程局部)时,初始化程序由等号后跟表达式组成。

此方法涵盖的过程是相同的。由于s2没有类数据类型而是const *char数据类型,因此它将使用标准转换将右侧字符串的值转换为左侧类型std::string的值。但是,如果显式声明了该函数,则不能像复制初始化程序那样进行标准转换,并且代码的编译将失败。

查看与2种初始化类型相比较的代码示例。这应该清除上面的任何混淆:

const *char

继续第三种情况,它甚至不是初始化的情况,它是一种分配的情况。就像你在评论中所说的那样,变量s3用默认字符串初始化。该字符串被" Hello"取代当你使用等号时这样做。这里发生的是当在 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时,调用string s3;的默认构造函数,并设置默认字符串值。当您使用 = 符号时,下一行中的 hello 将替换该默认字符串。

如果我们考虑哪种方式在跑步时的速度更有效,那么差异就是微不足道的。但是,如果我们单独执行此操作,则s1需要最快的运行时间:

std::string

这需要以下时间和内存来编译和运行:

  

编译时间: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秒。存在差异,但存在差异。

s3的第三种情况,如果按以下方式编码:

    int main(void)
    {
        string a = "Hello";
    }

具有完整的运行,编译时间和空间:

  

编译时间:0.32秒,绝对运行时间:0.14秒,CPU时间:0秒,内存峰值:3 Mb,绝对服务时间:0,47秒

我想在这里指出一些事情:第二种和第三种方法之间的运行时差异很可能是 NOT 零;相反,它是一个小于0.01秒的时间差,第三种方法需要更长的时间(s3)。那是因为它有2行代码可供操作;一个是变量的声明,另一个是字符串赋值给变量。

希望这能回答你的问题。

答案 3 :(得分:1)

如果某个类没有可访问的复制构造函数,则第二种初始化形式无效:

[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]$ 

不同之处在于,第二个正式创建了S类型的临时对象,使用值3初始化,然后将该临时对象复制到s2。允许编译器跳过副本并直接构造s2,但仅当副本有效时才会生成。