如何在构造函数中处理'this'指针?

Kyl*_*yle 18 c++ constructor boost shared-ptr

我有对象在其构造函数中创建其他子对象,传递'this',以便子进程可以将指针保存回其父对象.我在编程中广泛使用boost :: shared_ptr作为std :: auto_ptr或原始指针的更安全的替代品.因此,孩子将拥有诸如的代码shared_ptr<Parent>,并且boost提供shared_from_this()父母可以给孩子的方法.

我的问题是shared_from_this()不能在构造函数中使用,这不是真正的犯罪,因为"this"不应该在构造函数中使用,除非你知道你正在做什么并且不介意限制.

Google的C++样式指南指出构造函数应该只将成员变量设置为其初始值.任何复杂的初始化都应该采用显式的Init()方法.这解决了"这个构造函数"问题以及其他一些问题.

困扰我的是,现在使用代码的人必须记住每次构造一个对象时都调用Init().我可以想到强制执行此操作的唯一方法是通过断言已经在每个成员函数的顶部调用了Init(),但这样编写繁琐且执行起来很麻烦.

那边有什么习惯用法可以解决这个问题吗?

Joh*_*ing 16

使用工厂方法进行两阶段构造和初始化您的类,然后将ctor和Init()函数设为私有.然后没有办法错误地创建您的对象.只记得保持析构函数公共并使用智能指针:

#include <memory>

class BigObject
{
public:
    static std::tr1::shared_ptr<BigObject> Create(int someParam)
    {
        std::tr1::shared_ptr<BigObject> ret(new BigObject(someParam));
        ret->Init();
        return ret;
    }

private:
    bool Init()
    {
        // do something to init
        return true;
    }

    BigObject(int para)
    {
    }

    BigObject() {}

};


int main()
{
    std::tr1::shared_ptr<BigObject> obj = BigObject::Create(42);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

如果您想要反对堆栈,您可以使用上述模式的变体.如上所述,这将创建一个临时的并使用copy ctor:

#include <memory>

class StackObject
{
public:
    StackObject(const StackObject& rhs)
        : n_(rhs.n_)
    {
    }

    static StackObject Create(int val)
    {
        StackObject ret(val);
        ret.Init();
        return ret;
    }
private:
    int n_;
    StackObject(int n = 0) : n_(n) {};
    bool Init() { return true; }
};

int main()
{
    StackObject sObj = StackObject::Create(42);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 虽然John的答案没有任何问题,但我有点担心它会得到的赞成可能会告诉新手这就是所有类都应该用C++实现构造的方式.它不是 - 它应该很少使用. (6认同)
  • 这个术语是准确的,我知道没有更好的,但我会从Create返回一个智能指针. (2认同)

sbi*_*sbi 8

谷歌的C++编程指南在这里和其他地方一再被批评.这是正确的.

如果它隐藏在包装类后面,我只使用两阶段初始化.如果手动调用初始化函数会起作用,我们仍然会用C和C++编程,它的构造函数永远不会被发明.

  • +1.重要的是要记住Google的指南主要是为了*他们*使用而不是为整个C++社区编写,并考虑所有现有的代码和实践,而不是作为如何编写新的通用项目的指南. (3认同)

Kei*_*thB 5

根据具体情况,这可能是共享指针不添加任何内容的情况.任何时候终身管理都是一个问题,应该使用它们.如果保证子对象的生命周期短于父对象的生命周期,我认为使用原始指针没有问题.例如,如果父对象创建并删除子对象(并且没有其他对象),则不应该删除谁应该删除子对象.

  • 将父指针放入智能指针会让孩子控制父母的生命周期,这只是一个等待发生的错误.删除最后一个孩子,并且*poof!*你从地下拉出地毯. (4认同)