来自同一个原始指针的两个std :: shared_ptr

时间:2014-07-16 14:01:53

标签: c++ c++11

我无法理解为什么explicit shared_ptr( pointer p );无法保护开发人员不将p分配给另一个shared_ptr

我的想法在这里:

#include <iostream>
#include <memory>

template <typename T>
class ptr
{
    public:
        // ctor a) for lvalues
        explicit ptr(T*& value)  : value_(value) { value=nullptr;  }

        // ctor b) for rvalues pointer reference
        explicit ptr(T*&& value) : value_(value) { }

        ~ptr() { delete value_; }

        // for simplicity this is left public
        T* value_;
};


int main(int argc, char *rgv[])
{
      {
        printf("%10s | %10s | %10s\n", "raw", "p0", "p1");
        // create a raw pointer
        // BAD practice but still could happen 
        int* raw = new int(1);
        printf("%10x | %10x | %10x\n", raw, 0, 0);

        // init p0 from raw pointer ctor (a)
        ptr<int> p0(raw);
        printf("%10x | %10x | %10x\n", raw, p0.value_, 0);

        // init p1 from the same raw poiter again ctor (a)
        ptr<int> p1(raw);
        printf("%10x | %10x | %10x\n", raw, p0.value_, 0);

        // nothing bad happens val was set to nullptr 
        // before p1 construction
      }

    // in order to construct ptr from rvalues 
    // we use ctor (b)
    ptr<int> p2(new int());

      {
        printf("\n");
        // create a raw pointer
        int* raw = new int(1);
        printf("%10x | %10x | %10x\n", raw, 0, 0);

        // init p0 from raw pointer
        std::unique_ptr<int> p0(raw);
        printf("%10x | %10x | %10x\n", raw, p0.get(), 0);

        // init "accidentally" p1 from the same raw poiter again 
        std::unique_ptr<int> p1(raw);
        printf("%10x | %10x | %10x\n", raw, p0.get(), 0);

        // CRASH: double free or corruption
      }

    return 0;
}

鉴于上述代码,我有两个问题:

1)我是否错过了以这种方式实施ptr的任何一点:简而言之就是有任何问题    我没有看到ptr(T*& value)ptr(T*&& value) contructor?

2)STL决定不在shared_ptr构造之后不要避免这个可能的错误使原始指针不受影响的原因是什么?

1 个答案:

答案 0 :(得分:2)

  

我是否错过了以这种方式实施ptr的任何一点?

如果必须将类型转换应用于指针,例如

struct Base {/*...*/};
struct Derived : Base {/*...*/};

Derived * d = new Derived;
ptr<Base> p(d);

然后将临时Base指针传递给 rvalue 构造函数,d将保持不变。

(你可能会使用模板构造函数来解决这个问题,但可能会有更多的细节)。

当然,如果用户愚蠢地保持一个原始指针,他可能是愚蠢到保持两个。该方案只会使其中一个无效。

  

STL决定不在shared_ptr构建时不要忽略这个可能的错误,原始指针不受影响的理由是什么?

据推测,最小惊喜的原则。

通过区分智能指针和原始指针,并始终将原始指针视为危险的野兽来避免这样的错误。像这样的局部安全网只会让人更难发现等待咬你的微妙边缘情况。习惯使用智能指针,避免原始指针,除非在异常情况下(应用特殊注意),完全消除了与所有权相关的错误的可能性。

在C ++ 14中,std::make_unique(除了我们已经拥有的std::make_shared)意味着new根本不需要出现在您的代码中,使其直截了当,以避免任何可能的错误。