【问题标题】:Copy constructor vs assignment operator with STL vector具有 STL 向量的复制构造函数与赋值运算符
【发布时间】:2020-07-28 15:30:34
【问题描述】:

有这个课程:

class A
{
    int number;
    int number2;
public:
    A(int _number):number(_number),number2(0)
    {
        cout<<"Normal constructor\n";
    }
    A()
    {
        cout<<"Default constructor\n";
    }

    A(const A& source)
    {
        number = source.number;
        number2 = source.number2;
        cout<<"Copy constructor\n";
    }

    A & operator=(const A& source)
    {
        number = source.number;
        number2 = source.number2;
        cout<<"Assignment operator\n";
        return *this;
    }
};

如果vector&lt;A&gt; obj {1,2,3}被创建,normal constructor被调用3次,因为它没有被声明为explicit,因此它被用作converting constructor。然后copy constructor被调用了3次。

  • 是否可以在跳过复制操作时声明和实例化 vector

如果执行vector&lt;A&gt; obj_1;,则会创建一个可以容纳A 类型对象的空向量——没有调用构造函数但对象存在。 p>

  • 为什么没有调用构造函数?
  • 我是否声明了对象完全可以使用?

来自this link

  1. 复制构造函数用于从其他对象的数据初始化以前未初始化的对象。

  2. 赋值运算符用于将先前初始化的对象的数据替换为其他对象的数据。


执行obj_1 = obj,如果我的 obj_1 先前已初始化,会导致在我的类 A 中调用 copy constructor 而不是 operator= 函数,正如我所期望的那样?

另外,在vector 内部已经有一个operator= 函数。我怎么知道每个人什么时候被调用?

vector<A> obj {1,2,3};
vector<A> obj_1;
obj_1 = obj;  // Why copy constructor called instead of function operator= inside my class

【问题讨论】:

  • vector&lt;A&gt; obj_1; 是一个空向量。这就是没有构造函数调用的原因。
  • 如何声明一个空的东西?当我声明int a 时,a 为空但有数据
  • 因为向量使用动态分配。基本上你所拥有的是一个A* 的包装器。如果您使用A* foo;,您将拥有A*,但没有创建A
  • @JesperJuhl 你想告诉我什么?我应该选择初始化列表吗?
  • @CătălinaSîrbu 查看我的更新评论。

标签: c++ stl stdvector


【解决方案1】:

有什么方法可以在跳过复制操作时声明和实例化 vector

没有。当您执行vector&lt;A&gt; obj {1,2,3} 时,编译器会根据提供的值创建std::initializer_list&lt;A&gt;std::initializer_list 创建是您看到三个普通构造函数调用的原因。然后向量必须复制这些元素,因为这些元素的底层存储是const。没有办法通过列表初始化来解决这个问题。即使vector&lt;A&gt; obj {A(1),A(2),A(3)} 仍然会导致复制。

如果你不想这样,那么你可以做的一件事是使用reserve为元素创建存储,然后使用emplace_back直接构造向量中的对象,如

vector<A> obj;
obj.reserve(3);
for (int i = 1; i < 4, ++i)
    obj.emplace_back(i);

如果我的 obj_1 先前已初始化,则执行 obj_1 = obj 会导致在我的 A 类中调用复制构造函数而不是 operator= 函数,正如我所期望的那样?

这是因为obj_1 是空的。因为它是空的,所以没有元素可以调用赋值运算符。相反,它所做的是在 obj_1 中创建元素,这些元素是 obj 的副本,最有效的方法是只调用复制构造函数,而不是默认构造对象然后分配给它们。

如果你有

vector<A> obj {1,2,3};
vector<A> obj_1 {3, 4, 5};
obj_1 = obj; 

然后您会看到使用了赋值运算符,因为实际上存在要赋值的对象。

【讨论】:

  • 我不清楚。 obj_1 怎么可能是空的。我不是声明了它,这意味着它在记忆中有一些地方和一些价值吗?即使nullptr 或类似的东西(默认基础数据类型 - 在这种情况下vector 使用动态分配我认为nullptr 应该是正确的值)? 我没有这样做 vector&lt;A&gt; obj_1 = obj (虽然我不确定是否正确)
  • @CătălinaSîrbu 它是空的,因为里面没有元素。如果您调用size(),它将返回0。那里有一个vector,当你做obj_1 = obj; 它调用vector的operator =,只是vector的operator =足够聪明,知道它可以在需要在vector中创建元素进行分配时调用复制构造函数给他们。
  • 好的,如果我想调用我的类函数operator=,那应该是我的vector 的状态吗?它是否应该至少包含一个 A 类型的元素并初始化为一个值?
  • @CătălinaSîrbu 它需要包含与源向量一样多的元素。这看起来像vector&lt;A&gt; obj {1,2,3}; vector&lt;A&gt; obj_1(obj.size()); // this creates empty objects in the vector; obj_1 = obj; 然后你会看到所有元素都使用了赋值运算符。但是,这是您不想做的事情。只做你所拥有的并允许使用复制构造函数来创建obj_1中的元素会更有效@
猜你喜欢
  • 2013-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多