C++:两个自定义对象的总和,避免复制构造函数的重复调用

C++: Sum of two custom objects, avoid double call of copy constructor

提问人:Michel H 提问时间:3/23/2021 最后编辑:Vlad from MoscowMichel H 更新时间:3/23/2021 访问量:114

问:

在下面的示例中,我有两个类,第一个动态分配一个整数,第二个是第一个类的容器。

当我对两个容器对象求和时 (),复制构造函数被调用两次。在我看来,第二个发生在函数的“return”语句期间。如何优化以避免复制构造函数的第二次调用?operator+()operator+()

显然,这对于更复杂的应用程序来说是代表的,如果从逻辑上思考,只需要创建一个对象来获得总和(然后返回):

(这似乎是很多代码,但只有运算符和构造函数才能有效地进行求和。我避开了析构函数,以免使它更加混乱)。

主班

int main()
{
  NumberContainer a{1};
  NumberContainer b{2};
  NumberContainer c = a + b; // Copy constructor called twice!
  return 0;
}

数字类:

class Number
{
public:
  int* num;

  Number(int num) : num{new int{num}}
  {}
// Destructor...
};

容器类:

class NumberContainer
{
private:
  Number _numObj;
public:
  NumberContainer(int num) : _numObj{Number{num}}
  {}

  NumberContainer(const NumberContainer& source) : NumberContainer{*(source._numObj.num)}
  {
    std::cout<<"Copy constructor called" << std::endl;
  }

  NumberContainer(NumberContainer&& source) : NumberContainer(*(source._numObj.num))
  {
    std::cout<<"Move constructor called" << std::endl;
  }

  NumberContainer& operator=(const NumberContainer& source)
  {
    *(_numObj.num) = *(source._numObj.num);
    std::cout<<"Copy assignment called" << std::endl;
    return *this;
  }

  NumberContainer& operator=(NumberContainer&& source)
  {
    _numObj.num = source._numObj.num;
    source._numObj.num = nullptr;
    std::cout<<"Move assignment called" << std::endl;
    return *this;
  }

  NumberContainer& operator+=(const NumberContainer& source)
  {
    *(_numObj.num) += *(source._numObj.num);
    return *this;
  }

  NumberContainer operator+(const NumberContainer& source) const
  {
    NumberContainer copy{*this};
    return copy+=source;
  }
// Destructor...
};
C++ operator-重载 复制构造函数

评论

0赞 Sam Varshavchik 3/23/2021
您是否尝试过简单地实现为 ,从而在 C++17 中保证复制省略?operator+return NumberContainer(this->number+source.number);
1赞 PaulMcKenzie 3/23/2021
你没有提到你用什么编译器选项来构建你的程序。您应该测试经过优化的代码,而不是“调试”或未优化的构建。

答:

1赞 Vlad from Moscow 3/23/2021 #1

在运算符 + 中创建中间对象没有多大意义。

  NumberContainer operator+(const NumberContainer& source) const
  {
    NumberContainer copy{*this};
    return copy+=source;
  }

像这样定义它

  NumberContainer operator+(const NumberContainer& source) const
  {
    return     *(_numObj.num) + *(source._numObj.num);
  }

此外,复制构造函数可以定义如下

  NumberContainer(const NumberContainer& source) : _numObj{*(source._numObj.num)}
  {
    std::cout<<"Copy constructor called" << std::endl;
  }

评论

0赞 Michel H 3/23/2021
嗨,弗拉德,您是否正在强制从数字转换为 NumberContainer 返回值?这似乎很合适,但正如我之前所说,这是一个代表性的例子,说明类可能比只有一个成员变量要复杂得多。在一般情况下,您如何解决它?
0赞 Vlad from Moscow 3/23/2021
@MichelHeusser 您可以返回一个带支撑的列表,而无需创建中间对象。