在C++中创建对象时,如何将对象指针推到向量

How to push object pointer to vector when object is created in C++?

本文关键字:对象 指针 向量 C++ 创建对象      更新时间:2023-10-16

我正试图在创建对象的同时将对象指针添加到向量中。目前我已经在对象的构造函数中完成了这项工作,但现在我听说这是一种错误的方式,因为对象并没有完全在这一点上创建。

MyObject类构造函数:

// MyObject constructor
MyObject::MyObject() {
    // add object to vector of all objects
    MyObjectManager::Instance()->objects.push_back(this);
}

MyObject只是对象的基类。我还有MyRectangle类,它是从MyObject继承的,所以当我创建新的MyRectanger时,就会调用MyObject构造函数,并将我新创建的对象推送到MyObjectManager的向量中。

MyObjectManager是一个单例类,它保存所有对象的列表,并非常频繁地调用它们的虚拟Draw函数。这就是问题所在吗?MyObjectManager可能会在对象完全创建之前调用对象的Draw函数?

我可以制作一个单独的方法来将对象添加到向量中。类似这样的东西:

MyObject::Create() {
    // add object to vector of all objects
    MyObjectManager::Instance()->objects.push_back(this);
}

但我必须这样使用它:

MyRectangle *rect = new MyRectangle(0.5, 0.5, 0.1, 0.1);
rect->Create();

我只想能够简单地通过如下构造函数实例化新对象:

MyRectangle *rect = new MyRectangle(0.5, 0.5, 0.1, 0.1);

您可以在构造函数中做到这一点,不是吗?

MyRectangle::MyRectangle(const float& a, const float& b, const float& c, const float& d) {
  this->Create();
}

如果您有特殊的MyObjectManager类,您也可以将其用作对象的工厂。要阐明它,请考虑代码:

struct MyObjectManager {
    template <typename T, typename... Args>
    T * createObject(Args... args) {
        T *ret = new T(args...);
        m_objects.push_back(ret);
        return ret;
    }
    std::vector<MyObjects *> m_objects;
};

对象创建:

MyRectangle *rect = MyObjectManager::Instance()->createObject<MyRectangle>(1.0, 2.0, 3.0, 4.0);

也许您可以考虑使用工厂模式:

MyRectangle * factoryMyRectangle(float x, float y, float w, float h)
{
    MyRectangle *rect = new MyRectangle(x,y,w,h);
    rect->Create();
    return rect;
}

您可以拨打:

MyRectangle *rect = factoryMyRectangle(0.5, 0.5, 0.1, 0.1);

很大程度上取决于上下文。如果push_back是最后一个构造函数中的指令,并且没有派生类,应该没有问题。同样,如果你在单线程环境(并且由于您不执行任何操作锁定,您必须是),并且派生类不执行任何操作通过矢量中的指针,没有问题。你是允许具有指向尚未完全构造的对象的指针,只要你不尝试使用他们指向的实际对象。

这可能是一个问题的一种情况是,如果你在多线程环境中的基类构造函数。如果你将指针推到未完全构造为yes的对象,以及然后另一个线程接管,在矢量,并试图使用它,你就有麻烦了。有处理此问题的各种技术:最常见的可能是使用工厂函数来构造所有对象,并具有工厂函数做push_back,在构造函数完成。所以你永远不会打电话给new MyRectangle(...)工厂功能之外。(通常,工厂函数将是一个静态成员,构造函数将私人的,所以你可以保证这一点。)

请注意,如果您确实使用了工厂函数,您可能会希望将new的结果保留在智能指针中,直到push_back已完成:

std::unique_ptr<MyRectangle> tmp( new MyRectangle(...) );
MyObjectManager::Instance()->objects.push_back( tmp.get() );
tmp.reset()

如果您可以保证在对象完全构建之前不会对其进行访问,而只对其进行存储,那么像您那样使用this指针应该不会有问题。如果有另一个线程处理绘制更新,例如,轮询管理器类中的所有对象并定期调用它们的draw函数,那么这种保证就失效了。

看看这个问题和这个问题,了解更多信息。