我对C++很陌生,我对一些关于复制的C++约定有疑问.我已经google了一下,并没有真正找到这方面的良好指导,所以我转向你们好人.
假设您有一个对象代表一些技术上可复制的资源,但副本很昂贵,而且几乎总是错误的.你还应该为它实现一个拷贝构造函数吗?或者更好的做一个类似的成员函数make_copy()(对于你想要复制对象的极少数时间).
例如:假设您有一个表示存储在视频内存中的纹理的类.此资源在技术上是可复制的:您可以为其创建新句柄并复制内存(通过CPU或使用图形库调用).但总的来说,这不是你真正想做的事情.它很昂贵,而且通常做错了,而且可能非常浪费内存.但是,你可以想象它有意义的角落情况:截取屏幕截图并在其上应用过滤器.这些案件很少见,但它们会存在.
我之所以犹豫是否正在制作这样做的复制构造函数的原因是我觉得C++有点太急于复制东西了.也许它反映了这样一个事实:我对这种语言有点新意,但是因为C++会在各种情况下调用复制构造函数,而你可能不会这样做.喜欢:
void some_method(Texture t)
{
...
}
Texture t(<arguments>);
Texture t2 = t; // calls copy constructor
some_method(t2); // calls copy constructor
Run Code Online (Sandbox Code Playgroud)
我更倾向于这两行调用复制构造函数是编译器错误(因为我觉得它们很容易犯错误)并且如果你想真正制作副本,你需要非常明确地使用它并使用专用的会员功能.
这有什么标准做法吗?关于何时(而且不应该)编写复制构造函数的一些圣人建议?我错过了一些Scott Meyers的章节?或者我应该尽可能地做到这一点?
编辑:要清楚我的例子:显然,你应该通过引用传递参数,但我的观点是,这是一个非常容易犯的错误,只是省略了&符号.如果你这样做,编译器将很乐意用一个非常昂贵的副本替换廉价的pass-by-reference,我宁愿编译器不这样做.但我不知道,也许这不是人们通常在C++中犯的错误,而且我过于谨慎?
是否要使用它是您的调用,但这是一个相对较轻的语法模式:
struct ExplicitCopy {
// Implement as usual
ExplicitCopy() = default;
ExplicitCopy(ExplicitCopy &&) = default;
ExplicitCopy &operator = (ExplicitCopy &&) = default;
// Copying happens with an ADL call to this function
friend ExplicitCopy copy(ExplicitCopy const &orig) {
return orig;
}
private:
// Copy operations are private and can't be called accidentally
ExplicitCopy(ExplicitCopy const &) = default;
ExplicitCopy &operator = (ExplicitCopy const &) = default;
};
Run Code Online (Sandbox Code Playgroud)
然后,尝试复制实例将导致调用私有构造函数时出现编译器错误.
ExplicitCopy ec;
ExplicitCopy ec2 = ec; // Nope
ExplicitCopy ec3(ec); // Nope
ExplicitCopy ec4 = copy(ec); // Yes
Run Code Online (Sandbox Code Playgroud)
感谢copy elision,没有额外的构造函数调用.
这是一个观点问题,但是如果复制是有意义的(尽管要花钱),那么我会
Don't forget assignment operators for each case.
And if you follow the rule of zero then the language will do all of this for you.
An example is std::vector. Did you really want to copy 50,000 heavy vector elements? Maybe not, but at least you had the choice to do so.
Counter-examples include standard streams, which are not copyable… but this is because it literally makes no sense to copy a "stream of data" (streams aren't containers!). They're also not moveable, but that's another story.