【问题标题】:Why is copy constructor called twice?为什么复制构造函数被调用两次?
【发布时间】:2021-03-02 10:19:50
【问题描述】:

我有以下代码sn-p

#include <iostream>
#include <vector> 

class Move {
    private:
        int* data;
         
    public: 
        void set_data_value(int d) {
            *data = d; 
        }
        int get_data_value(){
            return *data; 
        }

        Move(int d);
        Move(const Move &source);
        ~Move();
};

Move::Move(int d) {
    std::cout << "ctor being called" << std::endl; 
    data = new int; 
    *data = d; 
}

Move::Move(const Move& source) {
    std::cout << "copy ctor being called" << std::endl;
    data = new int; 
    *data = *source.data;
}

Move::~Move() {
    std::cout << "deleting Move" << std::endl; 
    delete data; 
}
int main() {
    Move x{1};
    
    Move y{x}; 

    std::vector<Move> vec; 
    vec.push_back(x);
    vec.push_back(y);

    return 1; 

}

这是输出:

ctor being called
copy ctor being called
copy ctor being called
copy ctor being called
copy ctor being called
deleting Move
deleting Move
deleting Move
deleting Move
deleting Move

我的问题是:当我只看到 3 个副本时,为什么要调用 4 次复制构造函数? (1 个来自 Move y{x},两个来自两个 push_back() 调用)

【问题讨论】:

  • 不能保证您所描述的内容,但可能是由于在第一次调用push_back() 后向量只有1 的容量,因此必须在第二次调用中调整大小(并复制元素)致电push_back()

标签: c++ copy-constructor


【解决方案1】:

您错过了计算向量的重新分配。将此行添加到您的代码中:

int main() {
    Move x{1};
    
    Move y{x}; 

    std::vector<Move> vec; 
    std::cout << "capacity: " << vec.capacity() << "\n";
    vec.push_back(x);
    std::cout << "capacity: " << vec.capacity() << "\n";
    vec.push_back(y);
    std::cout << "capacity: " << vec.capacity() << "\n";

    return 1; 

}

那么可能的输出是:

ctor being called
copy ctor being called
capacity: 0
copy ctor being called
capacity: 1
copy ctor being called
copy ctor being called
deleting Move
capacity: 2
deleting Move
deleting Move
deleting Move
deleting Move

vectors 容量以0 开始,然后根据需要增加(2 或 3 的因素很常见)。可以看到,当容量从 1 增加到 2 时,会调用复制构造函数,将向量中已经存在的那个元素复制到内存中的不同位置。

请注意,上面的输出可以不同。分配策略受到微妙的优化。它要求push_back 具有摊销常数复杂性,这意味着容量不能线性增长。虽然这个因素不一定是2。一些实现使用3 或其他因素。

【讨论】:

  • 太棒了,非常感谢!有没有办法确保矢量移动而不是复制?
  • @LionellLohJianAn 我必须查一下才能确定。我认为当元素可移动时它会移动,但你的 Move 不是
【解决方案2】:

这是由于每次数组不再足够时向量的容量增加 您可以通过保留一些空间来防止这种情况reserve()

https://en.cppreference.com/w/cpp/container/vector/reserve

【讨论】:

  • 我只保留了关于容量和储备的部分,并赞成你的回答:)
  • 关于reserve()的点很有用,谢谢!
猜你喜欢
  • 2020-06-29
  • 1970-01-01
  • 2015-04-28
  • 2022-07-05
  • 2013-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多