我正在使用Visual Studio Ultimate 2013预览版,Windows 7。
我正在使用CRTP将任何类型的对象方便地推送到单独的向量中。
然而,结果很奇怪。您会看到我有两个类A
和B
,它们来自Container
。使用T* PushOne()
,新实例将被推送到静态向量中,并返回其地址以供使用。
出于某种原因,类A
的第一个实例化对象和类B
的第一个实例似乎共享相同的地址。
以下是代码:
template <typename T>
class Container{
public:
static std::vector<T> elements;
static T* PushOne(){
//Push a new T object into the vector
elements.push_back( T{} );
//Print out its address
std::cout << "Make " << typeid(T).name() << " at " << &elements[elements.size() - 1] << "\n";
//Return its address.
return &elements[elements.size() - 1];
}
};
template <typename T>
std::vector<T> Container<T>::elements;
class A : public Container<A>{
};
class B : public Container<B>{
};
int main(int argc, char** args){
std::cout << "First addresses:\n";
//a and c are assigned the address
auto a = Container<A>::PushOne();
auto b = Container<A>::PushOne(); //Problem gone if this is commented
auto c = Container<B>::PushOne();
std::cout << "\nLater addresses:\n";
std::cout << &Container<A>::elements[0] << "\n"
<< &Container<A>::elements[1] << "\n"
<< &Container<B>::elements[0] << "\n";
std::cin.get();
}
我机器上的一次运行输出:
First addresses:
Make class A at 00700350
Make class A at 006FA929
Make class B at 00700350
Later addresses:
006FA928
006FA929
00700350
如您所见,第一个和最后一个条目(分别存储在变量a
和b
中)首先打印相同的地址。
当我第二次打印地址时,我得到第一个A *的不同结果。
除非我注释掉auto b = ...
行,否则我总会得到相同的结果。如果我这样做,则会为a
和b
分配不同的地址。
答案 0 :(得分:4)
第二个push_back / PushOne导致您std::vector<A>
重新分配以重新分配,以便现在第一个A元素不再位于00700350
。
您的Later addresses
打印输出确认了这一点。
答案 1 :(得分:3)
当您将元素推送到向量时,最终它将需要分配新内存,并释放旧内存(其他分配可能使用)。所以,显然,当你第二次推回Container<A>
时,就会发生重新分配。然后,当你按下Container<B>
时,它的向量使用了另一个向量(Container<A>
)释放的内存。这完全没问题。