shared_from_this使用注意

文章目录

    • 1. shared_from_this只能被shared_ptr管理对象调用
    • 2. 禁止在栈/堆上构造对象
      • 2.1 更加优雅的方式
    • 3. 只能在栈上或者堆上构造对象

这里算是为我的智能指针学习补上最后一块知识。

1. shared_from_this只能被shared_ptr管理对象调用

在cppreference里有这么一句话
shared_from_this使用注意_第1张图片

这里提到了这么一句话,只允许在shared_ptr所管理的对象上调用shared_from_this。剩下的俩种管理,一种为栈对象,一种为被new分配出来的对象所管理。

class Foo
: public enable_shared_from_this<Foo>
{
     
public:
    shared_ptr<Foo> returnSp()
    {
     
        return shared_from_this();
    }
};

int main()
{
     
    Foo foo1;
    auto sp1 = foo1.returnSp();

    Foo *foo2 = new Foo();
    auto sp2 = foo2->returnSp();
}

会抛出std::__1::bad_weak_ptr: bad_weak_ptr这个异常。
显然,当我们需要这样使用的时候,应该在类的手段上来禁止这两种方法。

2. 禁止在栈/堆上构造对象

  1. 对于栈上使用对象来说,其在构造时候需要调用构造函数,在栈结束时要调用析构函数,因此二者中任何一个被不允许出现在栈上,就可以达到目的。
  2. 对于在堆上使用对象来说,就要明白new表达式干了什么,new实际上就干了俩件事。1. 分配内存,2.调用构造函数。反之,delete,则是1. 调用析构函数,2. 释放内存。

因此,如果我们禁掉构造函数,那么new和栈上都不可以构造对象。如果禁掉析构函数,则可以new,但是不能delete。(禁掉指将构造函数或者析构函数放到protected或者private下面)。

2.1 更加优雅的方式

但是对于C++11这种现代编程来说,除非为了效率使用new,(这样的话应该去用C而不是C++)。一般都是使用智能指针来做的。

class Foo
: public enable_shared_from_this<Foo>
{
     
protected:
    Foo() = default;
public:
    ~Foo() = default;
    static shared_ptr<Foo> Create()
    {
     
        shared_ptr<Foo> sp(new Foo());
        return sp;
    }

	void print()
	{
     
		cout << "hello" << endl;
	}
    shared_ptr<Foo> returnSp()
    {
     
        return shared_from_this();
    }
};

int main()
{
     
    auto sp = Foo::Create();
    sp->print();
}

但其实还是有不完美的地方,因为其友元依然可以创建栈上的对象。但是相较之前来说,这个类使用要求已经很严格了。

3. 只能在栈上或者堆上构造对象

  1. 只能在栈上。对于new表达式来说,其先使用operator new去分配空间,然后去调用placement new去构造。因此我们将类的operator new禁止就可以阻止在堆上建立对象
  2. 只能在堆上。编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。因此,将析构函数设为私有,类对象就无法建立在栈上了

你可能感兴趣的:(c++从零开始)