【问题标题】:How to push object pointer to vector when object is created in C++?在 C++ 中创建对象时如何将对象指针推送到向量?
【发布时间】:2014-01-01 04:05:26
【问题描述】:

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

MyObject 类构造函数:

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

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

MyObjectManager 是一个单例类,它保存所有对象的列表并非常频繁地调用它们的虚拟绘图函数。那是问题吗? 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);

【问题讨论】:

  • '非常频繁地调用他们的虚拟绘图函数。是这个问题吗?'很可能!
  • 关于在构造函数stackoverflow.com/a/3905886/356440中调用虚函数的问题,你可以查看这个答案

标签: c++


【解决方案1】:

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

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

【讨论】:

  • 这行得通吗?如果我在构造函数中调用 Create 函数,那么它与在构造函数中推送到向量不一样吗?
  • @user19985 不,不一样。如果在 MyRectangle 构造函数中调用 Create,则 MyObject 构造函数已经完成,那么就可以了。正如我在 cmets 中告诉你的那样,你可以看看这个描述这个问题 stackoverflow.com/a/3905886/356440 的答案。
  • @StephaneRolland 好的,谢谢。我实际上阅读了那个答案,但显然没有理解所有内容:)
  • @user19985 如果你必须记住的话,构造函数一个接一个地被调用,从基类到子类,然后到子子类等等。相反,请记住以相反的顺序调用析构函数。从子类,到基类,再到基类,直到层次结构的尽头。
【解决方案2】:

如果你有特殊的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);

【讨论】:

  • 感谢您的回答,这非常有用,但这次我会选择 Velthune 的回答。
【解决方案3】:

也许你可以考虑使用 factory 模式:

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);

【讨论】:

    【解决方案4】:

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

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

    请注意,如果您确实使用工厂功能,您可能会 想要将new 的结果保存在智能指针中,直到 push_back 已完成:

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

    【讨论】:

      【解决方案5】:

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

      查看this 问题和this 以了解更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-19
        • 2011-10-01
        • 2011-02-11
        • 1970-01-01
        • 1970-01-01
        • 2010-12-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多