毫无疑问,共享指针是个好主意。但是,只要大型程序包含原始指针,我认为使用共享指针就有很大的风险。主要是,您将失去对指向包含原始指针的对象的指针的实际生命周期的控制,并且错误将发生在难以查找和调试的位置。
所以我的问题是,是否没有尝试将不依赖于使用共享指针的“弱指针”添加到现代c ++中?我的意思是仅当指针在程序的任何部分被删除时,该指针将变为NULL。有没有理由不使用这种自制包装纸?
为了更好地解释我的意思,以下是我所做的“弱指针”。我将其命名为WatchedPtr。
Person
结果:
#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;
}
-已编辑
谢谢大家。到目前为止的评论和答案有一些澄清:
答案 0 :(得分:5)
弱指针依赖于智能指针基础结构的通知,因此您永远无法使用实际的原始指针进行操作。
可以想象一个unique_ptr
的扩展,它肯定支持弱指针。大概没有人急于实现这种功能的主要原因是,弱指针已经处于规模的“使用引用计数,一切都应该正常工作”的末端,而unique_ptr
处于“通过RAII管理您的生命”或者您不是真正的 C ++程序员”。弱指针还要求每个分配有一个单独的控制块,这意味着与WatchedPtr
相比,shared_ptr
的性能优势极小。
答案 1 :(得分:2)
我认为使用共享指针存在很大的风险。主要是,您将失去对指向包含原始指针的对象的指针的实际生命周期的控制,并且错误将发生在难以查找和调试的位置。
那你说
只是一个指针,该指针在程序的任何部分被删除后都会变为NULL。
看不到矛盾吗?
您不想使用共享指针,因为对象的生存期是在运行时确定的。到目前为止一切顺利。
但是,您希望指针在所有者删除时自动变为空。问题是,如果知道指针的寿命,则根本不需要它!如果您知道指针的生命周期何时结束,那么您应该能够删除该指针的所有实例,这有一种手段可以检查指针是否失效。
如果您有一个指针,您不知道所有者什么时候会释放它,并且对于弱者的观点没有办法检查或没有明显的副作用,那么您真的可以控制生命周期吗?你的指针?不是。
实际上,您的实现依赖于包含共享指针。从某种意义上说,这很有启发性,您需要某种形式的共享所有权才能实现可能具有弱指针的原始指针。然后,如果您需要共享所有权来实现带有弱引用的原始指针,则剩下一个共享指针。这就是为什么您提议的课程的存在是矛盾的。
std::shared_ptr
+ std::weak_ptr
用于解决“程序的某些部分不知道所有者何时释放资源”的问题。您需要一个std::shared_ptr
和多个std::weak_ptr
,以便他们知道何时释放资源。这些类具有在运行时检查变量生存期所需的信息。
或者相反,如果您知道指针的寿命,则可以使用该知识并找到一种方法来删除悬挂的指针,或者公开一种检查悬挂的指针的方法。
答案 2 :(得分:0)
通过阅读答案和评论以及C++ Core Guidelines by Bjarne Stroustrup & Herb Sutter,我得出了以下答案:
遵循准则时,不需要包含“新”和“删除”的“ WatchedPtr”。但是,对于我来说,出于调试/ QA目的,跟踪从智能指针获取的原始指针的有效性的方法仍然存在疑问。
详细信息:
原始指针应继续使用。由于各种原因。但是,显式的“ new”和“ delete”不应该。分别用shared_ptr / unique_ptr代替调用“ new”和“ delete”的情况。
在当前分配了原始指针的地方,没有必要用“ WatchedPtr”替换它。
如果将原始指针替换为分配了其他指针的原始指针,则在大多数情况下将替换为unique_ptr,在其他情况下将替换为shared_ptr。 “ WatchedPtr”(如果有的话)将从该点继续,从共享/唯一指针构建。