初始化..哪一个更有效?

时间:2009-03-12 03:29:16

标签: c++ constructor initialization

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

string strMyString = "SampleString";

string strMyString("SampleString");

提前致谢。

4 个答案:

答案 0 :(得分:21)

我回答了here

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

虽然字符串具体的简短解释。 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 一个接受初始值设定项的转换构造函数。所以它使用它。最后,它实际上与

相同
std::string s(std::string("hello"));

请注意,您的示例中使用的表单触发了所有

std::string s = "hello";

定义隐式转换。如果你想知道你的东西的初始化规则,你可以将构造函数标记为char const*显式,并且它不允许使用相应的构造函数作为转换构造函数

class string {
public:
    explicit string(char const* str) {
        // copy over...
    }
};

有了它,现在禁止使用copy initializationchar 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&);
};

实际上,只有直接初始化情况才有效。

答案 1 :(得分:7)

编译两者,查看汇编程序。首先是少一条指令......

; 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    :    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,Release设置)为这两个版本生成了相同的汇编程序。所以它在这个编译器中没有任何区别,你可以证明它。

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

其他答案都是正确的,但请记住它可能并不重要。这将是罕见的,非常罕见,非常罕见,字符串初始化效率将影响您的程序速度甚至只需几分之一秒。

问题本身是一个有趣,因为它有助于显示C ++构造函数和赋值的操作,但实际上如果你花时间尝试优化它(并且在SO上发布是足够的证据)你是..)你真的倾向于风车。

最好避免分散注意力并在别处付出努力。