在 C++ 11 中将 `nullptr` 作为 `std::shared_ptr` 返回是否安全?

问题描述

以以下代码片段为例:

template <typename FOO>
std::shared_ptr<FOO> createSharedPtr(bool yesNo) {
  if (!yesNo) {
    return nullptr;
  } else {
    return make_shared<FOO>();
  }
}

我认为上面的 return nullptr; 语句符合 C++ 11 标准,因为 nullptr 将用于在返回调用者时构造 null std::shared_ptr,如cppreference shared_ptr 描述:

constexpr shared_ptr( std::nullptr_t ) noexcept;            (2)

然而,我的一位同事一直坚持他应该选择 return shared_ptr<FOO>();,因为他找不到任何官方文档或示例将 nullptr 分配给 std::shared_ptr

我的理解正确吗?如果是,我应该给他看什么文件来证明我的意见?

更新 1

实际上我确实与他进行了讨论,引用了 cppreference shared_ptr,并且他现在的关注点似乎是:

这意味着使用 shared_ptr() 或 shared_ptr(nullptr)。 但是返回 nullptr 需要进行从 nullptr 到 shared_ptr 的转换,并且需要一个复制构造函数

如果我理解正确,他关心的是如何将 nullptr 构造为 shared_ptr。关于这一点,关键是从nullptrshared_ptr的隐式转换。这应该相当于:

class A {
 public:
  A(int a) : a_(a) {}

 private:
  int a_;
};

A a = 1;

我应该看哪个文档来说明上面代码的正确性?

更新 2

看起来 Converting constructor 可以解释这里的关键点。谢谢大家!

解决方法

他们的意思是一样的。在这里您甚至可以看到生成的汇编代码是相同的:https://godbolt.org/z/odKc4q9ja

如果您喜欢简洁和/或不喜欢 nullptr,您可以 return {} 以获得相同的效果。

,

您的同事似乎将 std::shared_ptr<Foo>(nullptr)std::shared_ptr<FOO>(static_cast<FOO*>(nullptr)) 混淆。你是对的:提到的重载已经保证返回的 shared_ptr 不包含资源。

但即使是 std::shared_ptr<FOO>(static_cast<FOO*>(nullptr)) 也是安全的。从标准来看,ctor的前提条件:

前提条件:表达式delete[] p,当T是数组类型时,或delete p,当T不是数组类型时,行为定义良好,不抛出异常。

delete static_cast<FOO*>(nullptr) 满足两个条件:它什么都不做。