0

我正在使用 Windows 7 的 Visual Studio Ultimate 2013 预览版。

我使用 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

如您所见,第一个和最后一个条目(分别存储在变量ab)首先打印相同的地址。

当我第二次打印地址时,第一个 A* 得到不同的结果。

除非我注释掉该行,否则我总是得到相同的结果auto b = ...。如果我这样做,ab分配不同的地址。

4

2 回答 2

4

第二个 push_back/PushOne 导致您重新分配std::vector<A>以增长它,因此现在第一个 A 元素不再位于00700350.

您的Later addresses打印输出证实了这一点。

于 2013-10-11T16:29:52.677 回答
3

当您将元素推送到向量上时,最终它将需要分配新内存,并释放旧内存(其他分配可能会使用)。因此,显然,当您第二次推迟 时 Container<A>,发生了重新分配。然后,当你 push 时Container<B>,它的向量使用了另一个向量(的Container<A>)释放的内存。这完全没问题。

于 2013-10-11T16:22:19.173 回答