为什么 std::unique_ptr 没有 const get 方法?

Why does std::unique_ptr not have a const get method?

我知道 std::unique_ptr 是这样的,可能不会改变以破坏向后兼容性,但我想知道是否有人有充分的理由说明规范的作者没有超载get 方法的 const 变体看起来像

const T* get() const;

遵循 unique_ptr 的意图 const

我最好的猜测是它试图镜像指针并像 T* const 而不是典型的 class。作为后续问题,如果我想在我的 class 的 const 实例中以类似 const 的方式保存一个指针,我是否应该使用 std::unique_ptr 以外的其他东西来保存数据?

更新

在我的例子中,我想保护自己不滥用 class 本身的指针。我正在编写一个 const 移动构造函数 MyClass(const MyClass&& other),并通过 std::copy 将数据从新实例复制到其他实例。追踪错误花了很长时间,因为我认为由于 const 保护,副本一定是正确的。我想弄清楚除了提供 const getter 并在复制时在 class 中使用它之外,我可以做些什么来保护自己免受此影响。

通过 unique_ptr 授予对对象的只读访问权限毫无意义。您只在转移所有权时传递 unique_ptr,为了在没有所有权转移的情况下访问对象,调用 up.get() 并将 const T* 传递给应该只读取的函数(或者如果指针永远不会 nullptr,评估 *(up.get()) 并传递 const T&).

也是合理的

作为奖励,这允许您将该函数用于存储在堆栈中的对象、嵌入到另一个对象中的对象,或者使用 unique_ptr 以外的智能指针管理的对象。

此处对所有 unique_ptr 参数传递案例(in/out、const/non-const 等)进行了很好的讨论:

出于同样的原因,取消引用时 T*constT&,而不是 T const&

pointer 的常量不同于 pointed-to.

的 pointness

get是const,不修改unique_ptr.

state

它的常量性不影响内容的常量性。

有传播常量的智能指针的想法,但 unique_ptr 不是那个野兽。

std::experimental::propogate_const 包装一个类似指针的对象并使 const 穿过它。

它或类似的东西可能会解决您的问题。

请注意,当我尝试像这样进行 const 传播时,我发现有一半的时间我发现我错了。但这里可能不是这样。

通常,以 const 方式处理 T*const 的正确方法是传递 T const&(或可空变体 T const*) .

智能指针伪装成原始指针。 如果你有 class 成员,它是原始指针并在 const 方法中使用它,你不能更新指针,但你可以修改指向的对象。 智能指针需要相同的行为。所以 std::unique_ptr::get 是一个 const 方法,但不会强制 return 指针指向 const 对象。

另请注意,您可以有一个指向 const 对象的指针。

MyClass *pointerToObject
std::unique_ptr<MyClass> smartPointerToObject;

// but you can have also a case
const MyClass *pointerToConstObject
std::unique_ptr<const MyClass> smartPointerToConstObject;

在最后一种情况下 std::unique_ptr::get 会 return 你所期待的。


基于以下评论:

只提供私有方法:

InnerClass& GetField() { return *uniquePtrToInnerClass; }
const InnerClass& GetField() const { return *uniquePtrToInnerClass; }

并在您的代码中使用它,您将在 const 方法中拥有内部 class 的 const 对象。

我认为这种担忧是有道理的, 每个解引用函数应该有 2 个版本,

e.g.
    const T* get() const;
    T* get();
    enter code here

我知道提供 "T* get() const" 的目的是为了轻松替换现有的原始指针用法。

但是由于 uniq ptr 表示所有权,因此有人能够通过不可变(常量)引用修改对象拥有的某些东西是不正确的[假设修改对象完全拥有的东西与修改对象相同本身 - 如果这是一个对象而不是 ptr,则为真。

可能最好的选择是 std 提供另一个版本的 Uniq ptr,它保持上述习语(唯一的其他选择可能是从 uniq ptr 派生一个新的 class 并提供 2 个版本用于取消引用)

因为就unique_ptr而言,获取内部原始指针引用是一个const操作。调用 .get() 并检索 std::unique_ptr 的内部原始指针不会更改 std::unique_ptr 对象本身的内部状态。因此,库设计者似乎选择将其标记为 const 而没有关注如果他们只是 return 直接非 const 引用它的底层对象会发生什么。

事实上,如果你在一个对象中有一个std::unique_ptr,并且你调用了那个对象的一个​​const成员函数,你仍然可以调用非const 对象 内部 std::unique_ptr 的成员函数。例如:

struct A {
    void Const() const { }
    void nonConst() { }
};

struct B {
    std::unique_ptr<A> a;
    void go() const {
        a->nonConst(); // OK
    }
};

虽然您不能从其 const 成员函数之一对对象的内部状态变量执行非 const 操作,但没有规则说您不能执行非 const 其他 个对象的操作。

您可能期望的是 constness 承诺从 unique_ptr 延续到也适用于访问它内部指向的内容,因此您期望 unique_ptr 写成这样:

template <typename T>
class cunique_ptr {
    T* ptr;
public:
    cunique_ptr() {
        ptr = new T;
    }
    ~cunique_ptr() {
        delete ptr;
    }

    // You can only get a non-const pointer to the internals from a non-const object
    T* get() { return ptr; }

    // The const member function carries over the const promise to access to its internals
    const T* get() const { return ptr; }
};

void test() {
    cunique_ptr<A> a;
    a.get()->nonConst();

    const cunique_ptr<A> ca;
    //ca.get()->nonConst(); //X fails: cannot call non-const member functions from const object
    ca.get()->Const();
}

然而,图书馆设计者似乎选择反对这种类型的保护,并让 const 承诺变得有点肤浅。