11

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

string strMyString = "SampleString";

或者

string strMyString("SampleString");

提前致谢。

4

4 回答 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来初始化对象。它看到一个接受初始化程序的转换构造函数。所以它使用它。最后,它实际上与sstd::stringstd::string

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

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

std::string s = "hello";

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

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

有了这个,现在(以及在其他各种地方)实际上禁止使用 acopy initialization和 a来初始化它!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&);
};

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

于 2009-03-12T03:36:04.520 回答
9

编译两者,看看汇编程序。第一个是更少的指令......

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

于 2009-03-12T04:14:15.083 回答
2

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

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

于 2009-03-12T03:54:53.740 回答
1

其他答案都是正确的,但请记住,这可能无关紧要。 这将是罕见的,非常罕见的,非常罕见的,字符串初始化效率会影响你的程序的速度,即使是几分之一秒。

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

最好避免分心并将精力花在其他地方。

于 2009-03-12T08:09:18.030 回答