该代码的最佳选择是什么?
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),但在这种情况下代码是正确的......
答案 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)} {}