为什么在所有情况下都允许使用指向shared_ptr构造的原始指针?

时间:2016-05-18 07:03:13

标签: c++ pointers c++11 shared-ptr

我正在阅读Top 10 dumb mistakes to avoid with C++11 smart pointer。 编号#5读取:

  

错误#5:没有将对象(原始指针)分配给shared_ptr as   一旦它被创建!

int main()
{
    Aircraft* myAircraft = new Aircraft("F-16"); 
    shared_ptr<aircraft> pAircraft(myAircraft);
    ...
    shared_ptr<aircraft> p2(myAircraft); 
    // will do a double delete and possibly crash
}

,建议类似于:

  

使用make_sharednew并立即构造指针   它

好的,毫无疑问是问题和建议。不过我对shared_ptr的设计有疑问。这是一个非常容易犯的错误,shared_ptr的整个“安全”设计可能会被非常容易的错误抛弃。

现在的问题是,是否可以通过shared_ptr的替代设计轻松修复,其中来自原始指针的唯一构造函数将来自r值引用? < / p>

template<class T>
struct shared_ptr{
    shared_ptr(T*&& t){...basically current implementation...}
    shared_ptr(T* t) = delete; // this is to...
    shared_ptr(T* const& t) = delete; // ... illustrate the point.
    shared_ptr(T*& t) = delete;
    ...
};

这样shared_ptr只能从new或某些工厂函数的结果初始化。

这是否是对库中C ++语言的开发不足?如果这很可能是滥用,那么从原始指针(l值)引用中获取构造函数有什么意义呢?

这是历史性事故吗? (例如,在引入r值引用之前提出了shared_ptr等)向后兼容性?

(当然有人可以说std::shared_ptr<type>(std::move(ptr));更容易捕获,如果真的有必要,还可以解决这个问题。)

我错过了什么吗?

3 个答案:

答案 0 :(得分:4)

指针很容易复制。即使您限制为r值参考,您也可以轻松地进行复制(例如,当您将指针作为函数参数传递时),这将使安全设置无效。此外,您会在模板中遇到问题,您可以轻松地将T* constT*&作为类型,并且您会遇到类型不匹配。

因此,您建议在没有显着安全性的情况下创建更多限制,这可能是为什么它不符合标准的原因。

make_shared的要点是雾化共享指针的构造。假设你有f(shared_ptr<int>(new int(5)), throw_some_exception())。标准不保证参数调用的顺序。允许编译器创建一个新的int,运行throw_some_exception然后构造shared_ptr,这意味着你可以泄漏int(如果throw_some_exception实际抛出异常)。 make_shared只是在其自身内部创建对象和共享指针,这不允许编译器更改顺序,因此它变得安全。

答案 1 :(得分:1)

在许多情况下,您可能无法拨打make_shared()。例如,您的代码可能不负责分配和构造有问题的类。以下范例(私有构造函数+工厂函数)在某些C ++代码库中使用的原因有多种:

struct A {
  private:
     A();
};

A* A_factory();

在这种情况下,如果你想将A*A_factory()粘到shared_ptr<>,你必须使用带有原始指针的构造函数而不是{ {1}}。

脱离我的头脑,其他一些例子:

  • 您希望使用make_shared()为您的类型获取对齐的内存,然后将其存储在posix_memalign()中,并使用调用shared_ptr<>的自定义删除工具(此用例很快就会消失)为语言添加对齐的分配!)。
  • 您希望将指向使用free()创建的内存映射区域的指针添加到mmap()中,并使用调用shared_ptr<>的自定义删除工具(此用例会在我们获取时消失一个标准化的shmem设施,我希望在接下来的几个月里继续努力。)
  • 您希望将分配的指针粘贴到带有自定义删除器的munmap()中。

答案 2 :(得分:1)

我对shared_ptr的设计没有任何特别的了解,但我认为最可能的解释是所涉及的时间表使这不可能实现:

在C ++ 11中,shared_ptr与rvalue-references同时引入。 shared_ptrboost中已经有一个有效的参考实现,因此可以预期它会相对较快地添加到标准库中。

如果shared_ptr的构造函数仅支持rvalue引用的构造,那么在编译器实现对rvalue引用的支持之前,它将不可用。

那时,编译器和标准的开发是异步得多的,因此,可能要花费,直到所有编译器都实现了支持(如果有的话)。 (2011年出口模板仍在人们的脑海中浮现)

此外,我认为标准委员会对标准化没有参考实现的API感到不自在,甚至在标准发布后也无法获得标准化。