毫无疑问,共享指针是个好主意。但只要大型程序包含原始指针,我认为使用共享指针就有很大的风险。主要是,您将失去对指向包含原始指针的对象的指针的真实生命周期的控制,并且错误将出现在更难以查找和调试的位置。
所以我的问题是,是否没有尝试向现代 c++ 添加一个不依赖于使用共享指针的“弱指针”?我的意思是只是一个指针,当在程序的任何部分删除时它会变成 NULL。有理由不使用这种自制的 wrapper 吗?
为了更好的解释我的意思,下面是我做的这样一个“弱指针”。我将其命名为 WatchedPtr。
#include <memory>
#include <iostream>
template <typename T>
class WatchedPtr {
public:
// the only way to allocate new pointer
template <typename... ARGS>
WatchedPtr(ARGS... args) : _ptr (new T(args...)), _allocated (std::make_shared<bool>(true)) {}
WatchedPtr(const WatchedPtr<T>& other) : _ptr (other._ptr), _allocated (other._allocated) {}
// delete the pointer
void del () {delete _ptr; *_allocated = false;}
auto& operator=(const WatchedPtr<T> &other) { return *this = other; }
bool isNull() const { return *_allocated; }
T* operator->() const { return _ptr; }
T& operator*() const { return *_ptr; }
private:
T* _ptr;
std::shared_ptr <bool> _allocated;
};
struct S {
int a = 1;
};
int main () {
WatchedPtr<S> p1;
WatchedPtr<S> p2(p1);
p1->a = 8;
std::cout << p1.isNull () << std::endl;
std::cout << p2.isNull () << std::endl;
p2.del ();
std::cout << p1.isNull () << std::endl;
std::cout << p1.isNull () << std::endl;
return 0;
}
结果:
1
1
0
0
-已编辑-
谢谢大家。到目前为止的评论和答案之后的一些澄清:
- 我为 WatchedPtr 提供的实现只是为了演示我的意思:一个指针,它不会从外部分配中获取拷贝,不能从外部删除,如果删除则变为 null。众所周知,实现远非完美,也不意味着完美。
- 混合使用 shared_ptr 和原始指针的问题非常普遍:A* 被保存为原始指针,因此在程序的某些位置创建并在程序的某些位置显式删除。 B 持有一个 A*,而 B* 持有为 shared_ptr,因此 B* 具有模糊的生命周期。因此,B 可能在 B 持有的 A* 被删除后存活很长时间。
- 在我看来“WatchedPtr”的主要用途是防御性编程。即检查 null 并为连续性做最好的事情(和调试错误)。 shared_ptr 可以做到,但是以一种非常危险的方式 - 它会隐藏和延迟问题。
- “WatchedPtr”(很少且明确的“所有者”)也可以有设计用法,但这不是主要思想。因为确实共享指针正在做这项工作。
- “WatchedPtr”的目的不是一次性替换程序中所有现有的原始指针。这与替换为 shared_ptr 的工作不同,恕我直言,它已为整个程序一次性完成。这对于大型项目来说是不现实的。
最佳答案
弱指针依赖于来自智能指针基础设施的通知,因此您永远无法使用实际的原始指针来做到这一点。
当然,可以想象 unique_ptr
的扩展支持弱指针。据推测,没有人急于实现这样一个特性的主要原因是弱指针已经处于“使用引用计数,一切都应该正常工作”的末尾,而 unique_ptr
处于“管理你的通过 RAII 的生命周期,或者你不是真正的 C++ 程序员”。弱指针还要求每个分配有一个单独的控制 block ,这意味着与 shared_ptr
相比,这种 WatchedPtr
的性能优势将是最小的。
关于c++ - 为什么原始指针没有 "weak pointer"?或者有吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55500183/