在 *modern* C++ 中,我应该如何管理 *unowned* 指针?
In *modern* C++ how should I manage *unowned* pointers?
在 modern C++ 中,我应该如何管理 unowned 指针?
我在想 unique_ptr
的 weak_ptr
之类的东西,但它似乎不存在。
例子
例如,如果我有一个 class A
拥有一个指针,我应该使用 unique_ptr<X>
而不是旧的 X*
指针,例如
class A
{
std::unique_ptr<X> _myX;
};
但是如果我有另一个使用此指针的 class B
,我该怎么办?使用 C 风格的指针,我会这样做:
class B
{
X* _someX;
};
这似乎是正确的,但从代码中看不出我引用了另一个对象的指针(例如 reader 可能认为我可能只是没有使用智能指针)。
我考虑了以下几点
std::shared_ptr<X>
- 似乎是引用计数的浪费,因为 A
保证比 B
. 长
std::weak_ptr<X>
- 仅适用于 shared_ptr
X&
- 仅当 X& 在 B 的构造函数中可用时才有效
这似乎是一个明显的问题,如果之前有人问过,我们深表歉意。我环顾四周,看到 问题,但不幸的是,OP 在一种特定情况下询问“使用 X* 是否可以”。我正在寻找我通常应该做的事情 而不是 X*,(如果有的话!)。
Bjarne Stroustrup weighed in on this matter.
Pointers are really good at pointing to "things" and T* is a really good notation for that... What pointers are not good at is representing ownership and directly
support safe iteration.
他提出两个建议:
- 考虑
T*
在现代 C++ 中表示“指向 T
的非拥有指针”
- 如果您希望变量声明明确记录这种非所有权,请使用
template<typename T> using observer_ptr = T*;
。
您的问题主要基于意见,但我们可以看看核心指南对此有何评论:
R.3: A raw pointer (a T*) is non-owning
Reason
There is nothing (in the C++ standard or in most code) to say otherwise and most raw pointers are non-owning. We want owning pointers identified so that we can reliably and efficiently delete the objects pointed to by owning pointers.
准则提倡当原始指针是拥有指针时永远不要使用它。一旦你这样做了,原始指针也很容易表明它是非拥有的。这种解释的缺点是:
Exception
A major class of exception is legacy code, especially code that must remain compilable as C or interface with C and C-style C++ through ABIs. The fact that there are billions of lines of code that violate this rule against owning T*s cannot be ignored. [...]
并非所有原始指针都是非拥有的,而且我们通常对此无能为力。但是,如果您的代码是在 C++11 之后编写的,那么使用原始指针应该足以表明它不是拥有指针。
That seems correct, but it isn't obvious from the code that I've referenced another object's pointer
理想情况下,应该显而易见。如果指针拥有资源,那么它应该是一个智能指针。由于它不是智能指针,这意味着它不应该拥有该资源。
也就是说,在现实中有 C/古老的 C++/设计糟糕的接口使用拥有指针,你可以像这样澄清缺乏所有权:
class B
{
X* _someX; // no ownership
};
也可以为此目的定义自定义 class 模板包装器,并且已经有一个 proposal 将此类模板包含在标准库中,该模板已被采纳为技术规范, 但还没有被采纳到标准中。据我了解,对于这种包装器是有用还是不必要,还没有达成共识。
https://abseil.io/tips/116 是对此处选项的很好讨论。如果你在建造时有东西,而且永远不需要重新指向它,那么 T&
可能很好。如果你不这样做,那么“嘿,这可能是空的”是该指针现实的一部分,T*
很好——现代 C++ 中的“原始”指针通常传达一个可选的、非拥有的引用。
在 modern C++ 中,我应该如何管理 unowned 指针?
我在想 unique_ptr
的 weak_ptr
之类的东西,但它似乎不存在。
例子
例如,如果我有一个 class A
拥有一个指针,我应该使用 unique_ptr<X>
而不是旧的 X*
指针,例如
class A
{
std::unique_ptr<X> _myX;
};
但是如果我有另一个使用此指针的 class B
,我该怎么办?使用 C 风格的指针,我会这样做:
class B
{
X* _someX;
};
这似乎是正确的,但从代码中看不出我引用了另一个对象的指针(例如 reader 可能认为我可能只是没有使用智能指针)。
我考虑了以下几点
std::shared_ptr<X>
- 似乎是引用计数的浪费,因为A
保证比B
. 长
std::weak_ptr<X>
- 仅适用于shared_ptr
X&
- 仅当 X& 在 B 的构造函数中可用时才有效
这似乎是一个明显的问题,如果之前有人问过,我们深表歉意。我环顾四周,看到
Bjarne Stroustrup weighed in on this matter.
Pointers are really good at pointing to "things" and T* is a really good notation for that... What pointers are not good at is representing ownership and directly support safe iteration.
他提出两个建议:
- 考虑
T*
在现代 C++ 中表示“指向T
的非拥有指针” - 如果您希望变量声明明确记录这种非所有权,请使用
template<typename T> using observer_ptr = T*;
。
您的问题主要基于意见,但我们可以看看核心指南对此有何评论:
R.3: A raw pointer (a T*) is non-owning
Reason
There is nothing (in the C++ standard or in most code) to say otherwise and most raw pointers are non-owning. We want owning pointers identified so that we can reliably and efficiently delete the objects pointed to by owning pointers.
准则提倡当原始指针是拥有指针时永远不要使用它。一旦你这样做了,原始指针也很容易表明它是非拥有的。这种解释的缺点是:
Exception
A major class of exception is legacy code, especially code that must remain compilable as C or interface with C and C-style C++ through ABIs. The fact that there are billions of lines of code that violate this rule against owning T*s cannot be ignored. [...]
并非所有原始指针都是非拥有的,而且我们通常对此无能为力。但是,如果您的代码是在 C++11 之后编写的,那么使用原始指针应该足以表明它不是拥有指针。
That seems correct, but it isn't obvious from the code that I've referenced another object's pointer
理想情况下,应该显而易见。如果指针拥有资源,那么它应该是一个智能指针。由于它不是智能指针,这意味着它不应该拥有该资源。
也就是说,在现实中有 C/古老的 C++/设计糟糕的接口使用拥有指针,你可以像这样澄清缺乏所有权:
class B
{
X* _someX; // no ownership
};
也可以为此目的定义自定义 class 模板包装器,并且已经有一个 proposal 将此类模板包含在标准库中,该模板已被采纳为技术规范, 但还没有被采纳到标准中。据我了解,对于这种包装器是有用还是不必要,还没有达成共识。
https://abseil.io/tips/116 是对此处选项的很好讨论。如果你在建造时有东西,而且永远不需要重新指向它,那么 T&
可能很好。如果你不这样做,那么“嘿,这可能是空的”是该指针现实的一部分,T*
很好——现代 C++ 中的“原始”指针通常传达一个可选的、非拥有的引用。