如何调用包含在std :: vector中的对象的构造函数?(How to call constructor of objects contained in a std::vector?)

编程入门 行业动态 更新时间:2024-10-11 01:15:03
如何调用包含在std :: vector中的对象的构造函数?(How to call constructor of objects contained in a std::vector?)

当我创建一个std ::对象的向量时,这些对象的构造函数并不总是被调用。

#include <iostream> #include <vector> using namespace std; struct C { int id; static int n; C() { id = n++; } // not called // C() { id = 3; } // ok, called }; int C::n = 0; int main() { vector<C> vc; vc.resize(10); cout << "C::n = " << C::n << endl; for(int i = 0; i < vc.size(); ++i) cout << i << ": " << vc[i].id << endl; }

这是我得到的输出:

C::n = 1 0: 0 1: 0 2: 0 ...

这是我想要的:

C::n = 10 0: 0 1: 1 2: 2 ...

在这个例子中,我不得不调整矢量大小,然后“手动”初始化其元素? 原因可能是矢量的元素没有按照有序的方式从第一个到最后一个进行初始化,因此我无法获得确定性行为?

我想要做的是容易地计算在程序中创建的对象的数量,在不同的容器中,在代码的不同点上,并为每个对象赋予一个ID。

谢谢!

When I create a std::vector of objects, the constructor of these objects is not always called.

#include <iostream> #include <vector> using namespace std; struct C { int id; static int n; C() { id = n++; } // not called // C() { id = 3; } // ok, called }; int C::n = 0; int main() { vector<C> vc; vc.resize(10); cout << "C::n = " << C::n << endl; for(int i = 0; i < vc.size(); ++i) cout << i << ": " << vc[i].id << endl; }

This is the output I get:

C::n = 1 0: 0 1: 0 2: 0 ...

This is what I would like:

C::n = 10 0: 0 1: 1 2: 2 ...

In this example, am I forced to resize the vector and then initialise its elements "manually"? Could the reason be that the elements of a vector are not initialised in an ordered way, from the first to the last, and so I cannot obtain a deterministic behaviour?

What I would like to do, is to easily count the number of objects created in a program, in different containers, in different points of the code, and to give a single id to each of them.

Thank's!

最满意答案

原因是vector :: resize通过调用自动提供的拷贝构造函数来插入副本,而不是您在示例中定义的构造函数。

为了得到你想要的输出,你可以显式地定义拷贝构造函数:

struct C { //.... C(const C& other) { id = n++; // copy other data members } //.... };

由于vector :: resize的工作原理(它有第二个可选参数,用作它创建的副本的“原型”,在C()情况下为默认值),这将在您的示例中创建11个对象'原型'和它的10份)。

编辑(在许多评论中包含一些好建议)

这个解决方案有几个缺点值得注意,以及一些可能产生更多可维护和合理代码的选项和变体。

这种方法确实会增加维护成本和风险。 每当添加或删除类的成员变量时,都必须记住修改拷贝构造函数。 如果您依赖默认的拷贝构造函数,则不必这样做。 解决这个问题的一种方法是将计数器封装在另一个类中( 像这样 ),这也可以说是更好的面向对象设计,但是当然你也必须记住许多可以通过多重继承产生的问题 。

它可以让其他人更难理解,因为副本不再是大多数人所期望的。 同样,处理您的类(包括标准容器)的其他代码可能会行为不当。 解决这个问题的一种方法是为你的类定义一个operator==方法(当你重写拷贝构造函数时,即使你不使用该方法,这也是一个好主意),从概念上来说,它的声音'也是一种内部文件。 如果你的类得到了很多的使用,你最终可能会提供一个operator=这样你就可以保持自动生成的实例id与应该在这个操作符下发生的类成员赋值的分离。 等等 ;)

如果你有足够的程序控制来使用动态创建的实例(通过new)并使用指向容器内的指针,它可能会消除'拷贝的不同id值'的整个问题。 这确实意味着你需要在某种程度上手动“初始化元素”,但编写一个函数可以让你得到一个完整的指向新的初始化实例的指针的函数并不是很多工作。 如果您在使用标准容器时始终如一地处理指针,则不必担心标准容器会在“封面”下创建任何实例。

如果你意识到所有这些问题,并相信你可以应付后果(当然这高度依赖于你的特定上下文),那么覆盖拷贝构造函数是一个可行的选择。 毕竟,语言功能是有原因的。 显然,它不像看起来那么简单,你应该小心。

The reason is that vector::resize inserts copies by calling the automatically provided copy constructor, rather than the constructors you have defined in your example.

In order to get the output you want, you can define the copy constructor explicitly:

struct C { //.... C(const C& other) { id = n++; // copy other data members } //.... };

Because of the way vector::resize works though (it has a second optional argument used as a 'prototype' for the copies it creates, with a default value in your case of C()), this creates 11 objects in your example (the 'prototype' and 10 copies of it).

Edit (to include some of the good advice in the many comments):

There are several downsides to this solution worth noting, as well as some options and variants that are likely to yield more maintainable and sensible code.

This method does add maintenance costs, and an amount of risk. You have to remember to modify your copy constructor whenever you add or remove members variables of the class. You don't have to do that if you rely on the default copy constructor. One way to combat this problem is to encapsulate the counter in another class (like this), which is also arguably better OO design, but then of course you also have to keep in mind the many issues that can crop up with multiple inheritance.

It can make it harder for other people to understand, because a copy is no longer exactly what most people would expect. Similarly, other code that deals with your classes (including the standard containers) may misbehave. One way to combat this is to define an operator== method for your class (and it may be argued that this is a good idea when overriding the copy constructor even if you don't use the method), to keep it conceptually 'sound' and also as a kind of internal documentation. If your class gets much use, you will likely also end up providing an operator= so that you can maintain the separation of your automatically generated instance id from class member assignments that should take place under this operator. And so on ;)

It might disambiguate the whole issue of 'different id values for copies' if you have enough control over the program to use dynamically created instances (via new) and use pointers to those inside containers. This does mean you need to 'initialise elements "manually"' to some degree - but it's not a lot of work to write a function that gives you back a vector full of pointers to new, initialised instances. If you consistently deal with pointers when using standard containers, you won't have to worry about the standard containers creating any instances 'under the covers'.

If you're aware of all those issues, and believe you can cope with the consequences (which is of course highly dependent on your particular context), then overriding the copy constructor is a viable option. After all, the language feature is there for a reason. Obviously, it is not as simple as it looks, and you should be careful.

更多推荐

本文发布于:2023-07-27 15:17:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1292341.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:函数   对象   vector   std   contained

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!