在构造函数中复制或引用?

时间:2016-04-17 22:40:41

标签: c++ c++11

该代码的最佳选择是什么?

class C
{
public:
    C(const std::string& str): str_(str) {}
private:
    std::string str_;
}

或者

class C
{
public:
    C(std::string str): str_(str) {}
private:
    std::string str_;
}

我是对的,在第二个代码中,我有两个复制,我在第一个代码中有一个?那么首先更好吗?

但有时我想创建C类:

C c(std::string());

我有一个警告(GCC),但在这种情况下代码是正确的......

4 个答案:

答案 0 :(得分:2)

为什么不在构造函数中简单地使用默认参数值

class C
{
public:
    C(const std::string& str = ""): str_(str) {}
                          // ^^^^
private:
    std::string str_;
};

并写

C c; 

而不是

C c(std::string());

请注意

C(const std::string& str = "")
声明

时,

无论如何都是多余的

C() = default;

构造

  

我是对的,在第二个代码中,我有两个复制,我在第一个代码中有一个?

由于std::string支持移动构造函数std::string(std::string&& s),因此您通常不需要为此案件担心。编译器将根据需要对其进行优化。

答案 1 :(得分:1)

我认为变体2在c++11天内更好,因为:

#include <iostream>

#define HI do { std::cout << __PRETTY_FUNCTION__ << "\n"; } while (false)

class String {
public:
    String() { HI; }
    ~String() { HI; }
    String(const String &) { HI; }
    String(String &&) { HI; }
    String& operator=(const String &) { HI; return *this; }
    String& operator=(String &&) { HI; return *this; }
};

#if 1
class C
{
public:
    C(const String &str): str_(str) {}
private:
    String str_;
};
#else
class C
{
public:
    C(String str): str_(std::move(str)) {}
private:
    String str_;
};
#endif

int main()
{
    C c{String()};
    std::cout << "2\n";
    String str;
    C c2{str};
    std::cout << "3\n";
    C c3{std::move(str)};
}

如果您启用变体1,则会获得:复制+复制+复制,

在变种2中你得到:移动+复制+移动+两个移动。

答案 2 :(得分:1)

C c(std::string());是一个函数声明。你的警告可能与此有关。

您的两个代码示例允许使用相同的语法来创建对象。您可以使用以下任一方法来避免函数声明问题:

C c = std::string();
C d{ std::string() };
C e("");

和/或正如其他人所建议的那样,制作一个默认参数。

关于1或2是否更好:2应更改为str_(std::move(str))。否则str_(str)会制作不必要的副本。

理论上,从包含长字符串的右值初始化选项2会更快,尽管您可能不会注意到任何差异。

答案 3 :(得分:0)

在大多数情况下(当初始化字符串已经创建并使用时),第一个变体会更好(因为第二个变量中缺少std :: move)。但是现在,在C ++ 11天里,最好的解决方案当然是涵盖所有可能的情况:

C() = default;
C(const std::string & str): str_{str} {}
C(std::string && str): str_{std::move(str)} {}
C & operator= (const std::string & str) { str_ = str; }
C & operator= (std::string && str): { str = std::move(str); }

或者,如果您知道自己在做什么,并且不再需要初始化字符串中的数据,则可以明确移动其内容:

C(std::string & str): str_{std::move(str)} {}