对于 std::string,复制初始化或直接初始化字符串文字更快吗?

问题描述 投票:0回答:4

我有以下问题。应该遵循哪一项更好?为什么?

string strMyString = "SampleString";

string strMyString("SampleString");
c++ constructor initialization stdstring
4个回答
22
投票

我回答了这里

我在这里回答的一件事是:都没有使用任何赋值运算符

对字符串特定事物的简短解释。

std::string
有一个构造函数,它接受一个接受
char const*
:

的参数
// simplified to a normal class declaration. std::string actually
// is a template instantiation. 
class string {
public:
    string(char const* str) {
        // copy over...
    }
};

现在你看到有一个构造函数,它带有一个指向字符的指针。这样它就可以接受字符串文字。我认为以下情况是显而易见的:

string s("hello");

它将直接调用构造函数并由此初始化

s
。这称为“直接初始化”。 初始化变量的另一种方法称为“复制初始化”。标准规定,对于复制初始化的情况,如果初始化器不具有正在初始化的对象的类型,则初始化器将转换为正确的类型。

// uses copy initialization string s = "hello"; 首先我们先来说一下类型

s
的类型为 std::string

    "hello"
  • 是一个数组,在这种情况下再次像指针一样处理。因此,我们将其视为
    char const*
  • 编译器寻找两种方法来进行转换。
    std::string 中有
  • 转换构造函数
吗?

初始化器的类型是否具有返回
    std::string
  • 的转换运算符函数?
  • 它将通过其中一种方法创建一个临时
  • std::string
    ,然后使用 
    s
复制构造函数

来初始化对象

std::string
。它看到
std::string
has
一个接受初始化器的转换构造函数。所以它使用它。最后,它实际上与 相同 std::string s(std::string("hello"));

请注意,示例中使用的表单触发了所有这些 std::string s = "hello";

定义了
隐式转换

。如果您想知道您的东西的初始化规则,您可以将采用

char const*
 的构造函数标记为类型的 
explicit

,并且它将不再允许使用相应的构造函数作为 conversion constructor


class string { public: explicit string(char const* str) { // copy over... } }; 这样,使用 copy initialization

char const*
 来初始化它实际上现在是被禁止的(以及在其他各个地方)!

现在,如果编译器不支持在各个地方省略临时变量。编译器可以假设在这种情况下有一个复制构造函数

复制
,并且可以消除临时字符串的额外副本,而是直接将临时 std::string 构造到初始化对象中。但是,复制构造函数必须特别可访问。所以,如果这样做的话,复制初始化是无效的

class string { public: explicit string(char const* str) { // copy over... } private: // ugg can't call it. it's private! string(string const&); };

现在实际上只有直接初始化的情况才有效。

编译两者,查看汇编器。第一个是少了一条指令......

; 9 : std::string f("Hello"); push OFFSET ??_C@_05COLMCDPH@Hello?$AA@ lea ecx, DWORD PTR _f$[esp+80] call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z ; 10 : std::string g = "Hello"; push OFFSET ??_C@_05COLMCDPH@Hello?$AA@ lea ecx, DWORD PTR _g$[esp+80] mov DWORD PTR __$EHRec$[esp+88], 0 call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z


9
投票

; 9 : std::string g1 = "Hello"; push OFFSET ??_C@_05COLMCDPH@Hello?$AA@ lea ecx, DWORD PTR _g1$[esp+136] call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z ; 10 : std::string f1("Hello"); push OFFSET ??_C@_05COLMCDPH@Hello?$AA@ lea ecx, DWORD PTR _f1$[esp+136] mov DWORD PTR __$EHRec$[esp+144], 0 call DWORD PTR __imp_??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z

...你瞧,第 
第二个

少了一条指令。

我们还看到这个编译器(Microsoft VC++ 2005,发布设置)为两个版本生成了相同的汇编程序。所以在这个编译器中没有什么区别,你可以证明这一点。

唯一真正的区别是,第一个在技术上需要使用复制构造函数,但允许编译器省略它,以便两种情况下的效率相同。

但是,第一个要求复制构造函数可访问(即不是私有的),即使它实际上并未使用。


2
投票

其他答案都是正确的,但也请记住,

这可能并不重要。

字符串初始化效率将非常罕见,非常罕见,非常罕见,甚至会影响程序的速度的一小部分。第二个。


1
投票
有趣

,因为它有助于展示 C++ 构造函数和赋值的操作,但在实践中,如果你花时间尝试优化它(并且在 SO 上发布就足以证明你是这样的......)你'真的很倾斜风车。 最好避免分心,把精力花在其他地方。

© www.soinside.com 2019 - 2024. All rights reserved.