如何在多个类中使用相同的unique_ptr

时间:2017-12-11 18:49:26

标签: c++ c++11 c++14 smart-pointers

我正在尝试更改我当前的设计,并希望使用智能指针(最好是unique_ptr,因为 Herb Sutter 说,如果有疑问,默认情况下更喜欢unique_ptr但是我很困惑,这适合我当前的设计,其中一个指针将被传递给多个类。

示例代码如下

class X {
private:
    ZHandler* _mZHandler; //change it as unique_ptr or shared_ptr??
public:
    X()
    {
        Z* zPtr = createUsingFactory(); // instantiated by legacy code factory function, createUsingFactory() is just representational
        _mZHandler = new ZHandler(zPtr);
    }
    ~X()
    {
        delete _mZHandler;
    }
    void callYfunc()
    {
        _mZHandler->funcY();
    }
};

//ZHandler wraps the calls to Z as well as serves as event listner to Z
class ZHandler : public Z::ZEventListner {
private:
    Z* _mPtrZ; 
public:
    ZHandler(Z* ptr) : _mPtrZ(ptr){}
    void funcY()
    {
        _mPtrZ->funcZ();
    }
    void funcNotifyEvent
    {
    }
};

class Z {
private:
    ZEventListner* _mZEventListner;
public:
    class ZEventListner{
        vitual void funcNotifyEvent() = 0;
    };
    void setEventListner(ZEventListner* ptr)
    {
        _mZEventListner = ptr;
    }
    ZEventListner* getEventListner(){return _mZEventListner};
    void funcZ(){}
    void funcNotify() //called by some other class
    {
        _mZEventListner->funcNotifyEvent();
    }
};

问题是,unique_ptr中的shared_ptr指针是使用ZHandler还是class X? (因此函数和指针会在其他类中改变), 如果我使用unique_ptr,那么我必须在ZHandler函数中移动setEventListner的ptr,一旦我这样做,原始指针将会丢失并进一步调用ZHandler <{1}}是不可能的。

2 个答案:

答案 0 :(得分:2)

智能指针完全是关于 所有权 。这意味着哪些对象负责删除其成员。因此,您应该查看哪些对象删除他们指向的内容。

如果设计不可能知道哪个指针将是最后一个引用对象(因此是用于删除它的那个),那么你应该使用<html lang="en"> <head> <meta charset="UTF-8"> <title>Sample Site</title> <link rel="stylesheet"href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/> </head> <body id="clrblk"> <div class="container"> <div id="loginbox" style="margin-top:50px;" class="mainbox col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2"> <div class="panel panel-info" > <div class="panel-heading"> <div class="panel-title">Sign In</div> <!--<div style="float:right; font-size: 80%; position: relative; top:-10px"><a href="#">Forgot password?</a></div>--> </div> <div style="padding-top:30px" class="panel-body" > <% if (message.length > 0) { %> <div class="alert alert-danger col-sm-12"><%= message %></div> <% } %> <form id="loginform" class="form-horizontal" role="form" method="post" action="/login"> <div style="margin-bottom: 25px" class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span> <input id="login-username" type="text" class="form-control" name="user_name" value="" placeholder="username"> </div> <div style="margin-bottom: 25px" class="input-group"> <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span> <input id="login-password" type="password" class="form-control" name="password" placeholder="password"> </div> <div class="input-group"> <!--<div class="checkbox"> <label> <input id="login-remember" type="checkbox" name="remember" value="1"> Remember me </label> </div>--> </div> <div style="margin-top:10px" class="form-group"> <!-- Button --> <div class="col-sm-12 controls"> <button id="btn-login" type="submit" class="btn btn-success">Login </button> </div> </div> <div class="form-group"> <div class="col-md-12 control"> <div style="border-top: 1px solid#888; padding-top:15px; font-size:85%" > Don't have an account! <a href="/signup"> Sign Up Here </a> </div> </div> </div> </form> </div> </div> </div> </div> </body> </html>

另一方面,如果只有一个指针将超过所有其他引用,并且总是需要删除对象,那么它应该是{{ 1}}。

大多数 拥有 指针(需要删除内容的指针)往往是std::shared_ptr

如果你有一个对象的指针,总是比指针更长,并被其他一些对象删除,那么你应该使用 原始指针 < / strong>或最好 参考

因此,您必须确定设计中哪些对象生存最长,哪些对象将负责销毁他们指向的对象并相应地选择指针。

共享指针:当您不知道哪个指针必须删除该对象时,因为您不知道哪个指针最后会超出范围(或被删除)。

唯一指针:当指针对象需要删除之前,指向的对象将从一个地方被销毁,而该对象的所有其他裁判都将过期。

原始指针/参考:当其他人负责删除该对象时,因为此指针/引用需要访问该对象将在此之前过期。

答案 1 :(得分:1)

这不是问题的直接答案,而是避免与智能指针混淆的方法。首先,不要使用unique_ptr或shared_ptr。而是花一天时间了解RAII并尝试实施自己的&#34; unique_ptr&#34; (你可以看一下stl代码)。这将让您了解unique_ptr的工作原理。然后尝试实现自己的&#34; shared_ptr&#34;。实现自己的共享ptr的最简单方法是使用内部引用计数的对象。

在您了解它们如何工作之后,使用unique_ptr或shared_ptr会失去它的魔力,您应该知道何时使用它。