是否可以/希望创建不可复制的共享指针模拟(以启用weak_ptr跟踪/借用类型语义)?
Is it possible / desirable to create non-copyable shared pointer analogue (to enable weak_ptr tracking / borrow-type semantics)?
问题:Unique_ptrs很好地表达所有权,但不能让weak_ptrs跟踪其对象生存期。 Shared_ptrs可以由weak_ptrs跟踪,但不能清楚地表达所有权。
建议的解决方案:派生一个新的指针类型(我称之为strong_ptr(,它只是一个shared_ptr,但删除了复制构造函数和赋值运算符,因此很难克隆它们。 然后,我们创建另一个新的borrowed_ptr类型(不容易存储(来处理weak_ptr访问对象时所需的临时生存期延长,从而可以避免在任何地方显式使用shared_ptrs。
这个问题 std::unique_ptr 的非所有权副本和这个问题 更好地按"所有权"和"参考"的不同类型shared_ptr? 两者都相似,但在这两种情况下,选择都被框定为简单的unique_ptr与shared_ptr,答案并没有提出一个令人满意的解决方案。 (也许我应该回答这些问题而不是问一个新的问题? 不确定在这种情况下正确的礼仪是什么。
这是一个基本的刺伤。 请注意,为了避免弱指针的用户必须转换为shared_ptr才能使用它,我创建了一个borrowed_ptr类型(感谢 rust 的名称(,它包装了shared_ptr但使用户很难意外存储它。 因此,通过使用不同的拙劣shared_ptr衍生物,我们可以表达预期的所有权并引导客户端代码正确使用。
#include <memory>
template <typename T>
// This owns the memory
class strong_ptr : public std::shared_ptr<T> {
public:
strong_ptr() = default;
strong_ptr(T* t) : std::shared_ptr<T>(t) {}
strong_ptr(const strong_ptr&) = delete;
strong_ptr& operator=(const strong_ptr&) = delete;
};
template <typename T>
// This can temporarily extend the lifetime but is intentionally hard to store
class borrowed_ptr : public std::shared_ptr<T> {
public:
borrowed_ptr() = delete;
borrowed_ptr(const borrowed_ptr&) = delete;
borrowed_ptr& operator=(const borrowed_ptr&) = delete;
template <typename T>
static borrowed_ptr borrow(const std::weak_ptr<T>& wp)
{
return wp.lock();
}
private:
borrowed_ptr(std::shared_ptr<T> &sp) : std::shared_ptr<T>(sp) {}
};
这看起来相当简单,并且比shared_ptr有所改进,但我找不到任何关于这种技术的讨论,所以我只能想象我错过了一个明显的缺陷。
谁能给我一个具体的理由,为什么这是一个坏主意? (是的,我知道这比unique_ptr效率低 - 对于 PIMPL 等,我仍然会使用 unique_ptr。
警告:我还没有在基本示例中使用它,但是它可以编译和运行:
struct xxx
{
int yyy;
double zzz;
};
struct aaa
{
borrowed_ptr<xxx> naughty;
};
void testfun()
{
strong_ptr<xxx> stp = new xxx;
stp->yyy = 123;
stp->zzz = 0.456;
std::weak_ptr<xxx> wkp = stp;
// borrowed_ptr<xxx> shp = wkp.lock(); <-- Fails to compile as planned
// aaa badStruct { borrowed_ptr<xxx>::borrow(wkp) }; <-- Fails to compile as planned
// aaa anotherBadStruct; <-- Fails to compile as planned
borrowed_ptr<xxx> brp = borrowed_ptr<xxx>::borrow(wkp); // Only way to create the borrowed pointer
// std::cout << "wkp: " << wkp->yyy << std::endl; <-- Fails to compile as planned
std::cout << "stp: " << stp->yyy << std::endl; // ok
std::cout << "bp: " << brp->yyy << std::endl; // ok
}
唯一所有权是唯一的,句号。一个地方拥有此资源,并将在该代码选择时释放它。
共享所有权是共享的。多个地方可以拥有此资源,并且只有在所有地方都这样做后才会释放资源。这是一个二进制状态:一个地方拥有资源,或者多个地方拥有资源。
您的所有权语义是独一无二的...除非他们不是。而以某种方式运作的规则,除非它们不这样做,这有点问题。
现在,您的具体实现充满了漏洞。shared/weak_ptr
都是这些类型接口的明确组成部分,因此从strong_ptr
中获取shared_ptr
非常容易。如果您有strong_ptr
的weak_ptr
(borrowed_ptr::borrow
需要(,那么您可以lock
它并获得shared_ptr
。
但是,即使您的接口正确隐藏了所有这些(也就是说,您创建自己的weak_ptr
等效类型并停止从shared_ptr
继承(,您的 API 也无法阻止某人将该borrowed_ptr
存储在他们想要的任何地方。哦,当然,他们以后不能更改它,但是在构建时将其存储在类成员中或堆分配一个或其他内容很容易。
因此,归根结底,锁定弱指针仍然代表所有权的主张。因此,指针堆栈的所有权语义仍然是共享的;只是鼓励 API 不要将共享所有权保留太久。
unique_ptr
没有"API 鼓励";它有 API强制。这就是赋予它独特所有权的原因。C++没有一种机制来创建要创建的所有权语义的类似强制。
鼓励在某种程度上可能是有用的,但仅仅拥有borrowed_ptr
可能与鼓励那些想要表达他们只是暂时声称拥有所有权的人一样有用。否则直接使用shared/weak_ptr
即可。也就是说,您的 API 应该明确识别它正在使用共享所有权,这样就不会有人被愚弄而产生其他想法。
- 光线跟踪器灯光反射错误
- 人脸跟踪arduino代码的优化
- CLANG 编译器 说:变量"PTR"可能未初始化
- 跟踪滚动条上的鼠标事件
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 如何使用新运算符跟踪在循环中创建的 QLabel
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- C++:跟踪类对象
- 用于解析 win64 堆栈跟踪的命令行客户端(可以访问符号服务器)
- 跟踪日志中的T.11803()是什么意思?
- 为共享 ptr 向量实现复制 c'tor?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 我能做些什么来跟踪矢量元素?
- 两个进程可以通过跟踪附加到同一个 PID 吗?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 提升堆栈跟踪不显示函数名称和行号
- cygwin_exception::open_stackdumpfile:将堆栈跟踪转储到 class4.exe.sta
- 引用 std::shared:ptr 以避免引用计数
- 如何按指针查看堆栈跟踪