当我创建一个对象的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.
谢谢!
解决方法
原因是
vector::resize通过调用自动提供的复制构造函数而不是您在示例中定义的构造函数来插入副本.
struct C { //.... C(const C& other) { id = n++; // copy other data members } //.... };
因为vector :: resize的作用方式(它有一个第二个可选参数,用作其创建的副本的“原型”,在C()的情况下使用默认值),这将在您的示例中创建11个对象“原型”和10个副本).
编辑(包括许多意见中的一些好建议):
这个解决方案有几个缺点值得注意,以及一些可能产生更可维护和明智的代码的选项和变体.
>这种方法会增加维护成本和风险.每当您添加或删除类的成员变量时,都必须记住修改您的副本构造函数.如果您依赖于默认的复制构造函数,则不必执行此操作.打击这个问题的一个办法就是将柜台封装在另一个类(like this)中,这也可以说是更好的OO设计,但是当然你还必须牢记the many issues that can crop up with multiple inheritance.
>它可以使其他人更难理解,因为副本不再是大多数人所期望的.类似地,处理您的类(包括标准容器)的其他代码可能会不正当行为.解决这个问题的一个方法是为你的类定义一个operator ==方法(而且may be argued这是一个很好的主意,当覆盖复制构造函数,即使你不使用该方法),保持概念上的“声音”和也是一种内部文件.如果你的类得到很多的使用,你可能会最终提供一个operator =,这样你可以保持自动生成的实例id与这个操作符下的类成员赋值的分离.等等