【问题标题】:explicit copy constructor compile error显式复制构造函数编译错误
【发布时间】:2015-06-10 22:14:49
【问题描述】:

我在检查 C++ 中的运算符重载时遇到了一些我没想到的东西,对此我有些怀疑。

我的复制构造函数被声明并实现为

explicit Vector(const Vector& v);

Vector::Vector(const Vector& v) :
_x(v._x), _y(v._y), _z(v._z) {}

然后我重载了复合赋值运算符

Vector Vector::operator+(const Vector& v) const
{
    Vector tmp(*this);
    tmp += v;
    return tmp;
}

Vector Vector::operator-(const Vector& v) const
{
    Vector tmp(*this);
    tmp -= v;
    return tmp;
}

但是,在 return 语句中,我收到错误消息 no matching constructor for initialization of 'Vector'

由于我添加到构造函数中的唯一内容是 explicit 关键字,因此我将其删除并且代码编译得很好,为什么?

我也在检查 C++11 的新内容,发现我可以像移动构造函数一样声明我的构造函数

explicit Vector(const Vector&& v);

并且代码编译得很好。如果我这样做,我是否必须同时拥有复制和移动构造函数?

explicit Vector(const Vector& v);
explicit Vector(const Vector&& v);

或者只有移动构造函数可以正常工作?如果我想坚持 C++11,正确的做法是什么?

【问题讨论】:

  • Explicit copy constructor 的可能重复项
  • +=-= 很可能正在制作导致错误的隐式复制。
  • 不是答案,而是对您的代码的评论。根本没有理由定义这样的复制构造函数,因为默认构造函数的作用完全相同。通常也有理由显式声明复制构造函数,因为它的目的是防止隐式类型转换。
  • @MikeMB "显式声明复制构造函数,因为它的作用是防止隐式类型转换" 比如?
  • @curiousguy:抱歉,措辞不当:应该阅读“通常没有理由显式声明复制构造函数,因为它的 [显式关键字] 目的是防止隐式类型转换。”这不是制作副本时发生的情况。

标签: c++ c++11 constructor


【解决方案1】:

你定义了一个显式的拷贝构造函数,但是函数

Vector Vector::operator+(const Vector& v) const

Vector Vector::operator-(const Vector& v) const

由于explicit,必须按值返回,并且不能再返回了(换句话说,他们不能将tmp复制到返回的对象中)。

我也在检查 C++11 的新内容,发现我可以像移动构造函数一样声明我的构造函数 explicit Vector(const Vector&& v); 并且代码编译得很好。如果我这样做,我是否必须同时拥有复制和移动构造函数?

我不确定我理解你的意思。如果您只声明一个显式移动构造函数(这将阻止编译器生成默认的复制构造函数),您将遇到同样的问题。我无法生成“可编译”代码。

【讨论】:

  • 我想我把事情搞砸了。返回的值,是左值还是右值?如果它是一个 rvalue,难道我不能不复制tmp,而是使用 C++11 中新的移动构造函数或移动操作吗?如果它是一个 lvalue 函数是否总是复制该值?编译器有什么优化吗?
  • @BRabbit27 返回是一个右值,编译器会尽可能执行优化(称为返回值优化,或RVO)。但是,如果您声明移动/复制构造函数explicit,即使原则上优化是可能的,编译器仍然会抱怨explicit 业务。这主要是因为编译器首先对您的程序进行正确性分析,然后再进行优化。代码在优化阶段之前应该是有效的 C++。
  • @BRabbit27 和 C++11 中,编译器首先尝试移动返回的对象(如果可能),如果没有,它会寻找一个复制构造函数来复制它,如果它仍然没有找不到它会发出错误。就是这种情况,您没有任何隐式复制/移动构造函数。
  • 所以,我想要问的问题是:我什么时候应该在构造函数中使用显式?如果我只是不把显式关键字放在那里,我的代码在编译和最佳实践方面应该没问题?
  • @BRabbit27 的想法是,如果您将复制 ctor 标记为 explicit,那么编译器希望“看到”它的直接调用,例如 Foo copy(original),而不是 Foo copy = original。后一种情况是隐式复制。在向/从函数传递/返回时也会发生同样的情况,您不会“看到”代码中拼写出的复制构造函数,因此复制是隐式的。因此,explicit 禁止这样做。
【解决方案2】:

按值返回对象要求可以执行隐式复制构造。明确复制构造函数可以防止这种情况发生。

无论编译器是否选择不调用复制构造函数(例如返回值优化)都是如此。

【讨论】:

    猜你喜欢
    • 2016-12-23
    • 1970-01-01
    • 1970-01-01
    • 2012-07-13
    • 1970-01-01
    • 1970-01-01
    • 2015-03-12
    • 2018-11-06
    相关资源
    最近更新 更多