【问题标题】:Why Copy constructor is called along with Move Constructor?为什么复制构造函数与移动构造函数一起调用?
【发布时间】:2017-12-26 17:10:21
【问题描述】:

这个问题看起来很奇怪,但我已经检查过多个编译器。在我的代码中,我有一个 Move Constructor 和一个 copy constructor 作为

class A {
    int val;
public:
    A(int var) : val(var)  {
    }
    A( A && a1) {
        cout<<"M Value -> "<<a1.val<<endl;
        cout<<"Move Cons..."<<endl;
     }
    A(const A & a1) {
        cout<<"Copy Cons.."<<endl;
        cout<<"Value -> "<<a1.val<<endl;
    }
};

如果我将main 函数写为

int main()
{
    vector<A> v1;
    A a2(200);
    v1.push_back(move(a2));              
}

输出是

M Value -> 200
Move Cons...

这是意料之中的,但如果我将 main 函数更改为

int main()
{
    vector<A> v1;
    A a2(200);
    v1.push_back(A(100));
    v1.push_back(move(a2));

}

我得到以下输出

M Value -> 100
Move Cons...
M Value -> 200
Move Cons...
Copy Cons..   // unexpected
Value -> 0    // unexpected

任何人都可以帮助我了解copy constructor 在何处以及如何被调用.. 也具有价值0

谢谢

【问题讨论】:

  • Vector 需要重新分配其存储空间才能增长,并将第一个元素复制到新存储空间。标记移动构造函数noexcept,然后一个好的实现将能够移动元素。
  • 至于值 0 - 你的复制和移动构造函数实际上并没有复制任何东西,并且保持 this-&gt;val 未初始化。当通过访问未初始化的对象进一步移动或复制此类对象时,您的程序会表现出未定义的行为。在您的情况下,val 中不可预测的值恰好是 0。
  • std::vector 的大多数(至少如果它们符合)标准库实现只会在它们包含的元素满足 std::move_if_noexcept 时移动元素,因为 vector 需要实现强异常保证。如果他们不能移动,他们将退回到复制。让你的移动构造函数noexcept.
  • 您还可以在推回之前保留存储以避免向量中的重新分配:v1.reserve(2);
  • Daksh,我回答了你的问题。

标签: c++ c++11 c++14 c++17


【解决方案1】:

原因已在 cmets 中得到解答。 我将尝试说明发生了什么。

步骤:

vector&lt;A&gt; v1;

  1. 向量的分配。它在内部为一个元素保留空间。

v1.push_back(A(100));

  1. 在向量内构造和移动A(100)

v1.push_back(move(a2));

  1. 由于您尝试插入一个超出实际最大大小的新元素,因此会将向量重新分配到新的内存空间。请记住,std::vector 将其内容保存在连续的内存中。
  2. a2 移动到v1 中。
  3. 将原始v1 的其余元素(在本例中仅为第一个元素)复制到新的v1

内存:

1) ## v1[undef ] #########################
2) ## v1[A(100)] #########################
3) ##   [A(100)] ### v1[undef,  undef ] ##
4) ##   [A(100)] ### v1[undef,  A(200)] ##
5) ##   [A(100)] ### v1[A(100), A(200)] ##

补充说明:

与值 0 相关,这是因为这些复制和移动构造函数实际上什么都不做,val 的值仍未定义。 使用适当的构造函数,这个日志应该是 100。

如果将移动构造函数标记为noexcept,它将在重新分配过程中使用,而不是复制一个。

您可以使用v1.emplace_back(100) 代替v1.push_back(A(100)) 来避免移动。

【讨论】:

  • 空向量可能没有为一个元素分配空间,但第一次调整大小是不可见的
  • @Caleth,你很可能是对的。由于向量的增长依赖于实现,并且我们不使用显式调整大小,因此不清楚。因此,为了清晰起见,我尝试使其尽可能简单。
猜你喜欢
  • 2015-06-10
  • 1970-01-01
  • 2018-02-03
  • 2013-04-25
  • 1970-01-01
  • 2012-04-29
  • 1970-01-01
  • 2014-01-24
相关资源
最近更新 更多