【发布时间】:2018-08-27 16:28:28
【问题描述】:
以下代码是我正在处理的项目中的一个最小示例。主要问题是我想减少对复制构造函数的调用次数,但我不清楚这样做的正确方法。
#include<iostream>
class MyClass
{
public:
MyClass() {std::cout << "Default Constructor\n";}
MyClass(const MyClass &input) {std::cout << "Copy Constructor\n";}
MyClass & operator=(const MyClass &input)
{std::cout << "Assignment\n"; return *this;}
MyClass & operator+=(const MyClass &input) {return *this;}
friend MyClass operator+(MyClass lhs,const MyClass &);
};
MyClass operator+(MyClass lhs,const MyClass &rhs)
{lhs+=rhs;return lhs;}
int main()
{
MyClass a,b,c;
c=a+b;
return 0;
}
当我运行代码时,输出是:
Default Constructor
Default Constructor
Default Constructor
Copy Constructor
Copy Constructor
Assignment
在a、b、c的构造中调用了三个默认构造函数。
operator+ 中的第一个参数调用两个复制构造函数,operator+ 的 return 调用。
赋值将a+b赋值给c的结果。
主要问题:在我的应用程序中,复制构造函数很昂贵(它涉及内存分配)。另一方面,转让相对便宜。减少对复制构造函数的调用的正确方法是什么?
我考虑了一些解决方案,但没有一个能让我满意:
据我了解,从阅读中,operator+ 不应该有第一个参数的引用,因为这有助于链接临时对象。因此,这个拷贝构造函数似乎是不可避免的。
以下代码明显更快(由于没有复制构造函数调用):
c = a; c += b;我可以使用这种格式编写代码,但这需要更精细的方法。我希望编译器比我自己进行这些调整更聪明。我可以实现一个函数
add(MyClass &,const MyClass &,const MyClass &);,但这失去了使用加法运算符的便利性(并且由于我使用的不同数据类型的数量而需要大量(无意识的)编码)。我查看了这些问题,但在这种情况下我没有看到任何可以提高性能的建议:
Copy constructor called twice、Copy constructor called twice 和 Conditions for copy elision
对 cmets 的回应:
私有数据包括 MPFR 和 MPFI,构造函数包括该数据的初始化。也许构造函数的不同实现是合适的,但我不确定。
我考虑了一个移动构造函数,但有时我也想要一个复制分配。从cppreference 看来,这些不能共存(或者至少在我最初尝试时出现错误)。看来这应该是最好的选择了。
【问题讨论】:
-
为什么不将(常量)引用传递给
operator+函数? -
“据我了解,从阅读中,operator+ 不应该有第一个参数的引用” - 你从哪里读到的?
-
并根据this canonical implementation reference binary operators 应该相互实现。就像使用
operator+=来实现operator+。在那种的情况下,你应该按值传递第一个参数。 -
有足够的信息建议您定义一个移动构造函数,并且您字面上不会有复制构造函数调用。
-
我同意这个评价。 move-ctor 和 move-assignment 都可以使用。 See it live。坦率地说,如果您的设计允许(很可能),我会同时实现它们。
标签: c++ copy-constructor rvo