我想要一个带有指针成员变量的类。该指针应指向可以堆栈分配或堆分配的对象。但是,此指针不应具有任何所有权。换句话说,当指针超出范围时,根本不应该调用delete。我认为原始指针可以解决问题...但是,我不确定是否有比原始指针更好的C ++ 11方法?
示例:
class foo{
public:
bar* pntr
};
int main(){
bar a;
foo b;
b.pntr=&a;
}
答案 0 :(得分:18)
原始指针在这里完全没问题。 C ++ 11没有任何其他“哑”智能指针处理非拥有对象,所以你不能使用C ++ 11智能指针。有一个针对非自有对象的“愚蠢”智能指针的提议:
已经通过实验实施为http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4282.pdf(感谢@ T.C。提示)。
另一种方法是使用智能指针和自定义删除器,它不执行任何操作:
#include <memory>
int main()
{
int a{42};
auto no_op = [](int*){};
std::unique_ptr<int, decltype(no_op)> up(&a, no_op);
}
或者,如@ T.C所述。在评论中,std::experimental::observer_ptr
。
正如Orbit中的@Lightness Races所提到的,std::reference_wrapper
也可能是一个解决方案,因为后者也是一个非拥有的智能指针。但是,std::weak_ptr
只能由std::weak_ptr
或其他std::weak_ptr
构建。一个严重的缺点是std::shared_ptr
是一个“重”对象(因为内部引用计数机制)。请注意,即使在这种情况下,std::shared_ptr
也必须有一个简单的自定义删除器,否则它会破坏堆栈以指示自动变量。
答案 1 :(得分:3)
在这里使用原始指针是完全正确的,因为您不打算让指针拥有指向的资源的所有权。
答案 2 :(得分:0)
如果通过&#34;更好的方法&#34;你是说&#34;更安全的方法&#34;然后是的,我已经实施了一个非拥有的&#34;智能指针在这里:https://github.com/duneroadrunner/SaferCPlusPlus。 (无耻的插件警报,但我认为这与此相关。)所以你的代码看起来像这样:
#include "mseregistered.h"
...
class foo{
public:
mse::TRegisteredPointer<bar> pntr;
};
int main(){
mse::TRegisteredObj<bar> a;
foo b;
b.pntr=&a;
}
TRegisteredPointer&#34;更聪明&#34;而不是原始指针,它知道什么时候目标被摧毁。例如:
int main(){
foo b;
bar c;
{
mse::TRegisteredObj<bar> a;
b.pntr = &a;
c = *(b.pntr);
}
try {
c = *(b.pntr);
} catch(...) {
// b.pntr "knows" that the object it was pointing to has been deleted so it throws an exception.
};
}
TRegisteredPointer的性能成本通常低于std :: shared_ptr。当你有机会在堆栈上分配目标对象时,要低得多。它仍然相当新,但还没有很好的文档记录,但是该库包含了它的使用注释示例(在文件&#34; msetl_example.cpp&#34;,下半部分)。
该库还提供了TRegisteredPointerForLegacy,它比TRegisteredPointer慢一些,但在几乎任何情况下都可以用作原始指针的替代品。 (特别是它可以在完全定义目标类型之前使用,而TRegisteredPointer则不然。)
就您的问题的情绪而言,我认为它是有效的。到目前为止,C ++程序员至少可以选择避免无效内存访问的不必要风险。原始指针也可以是一个有效的选项,但我认为它取决于上下文。如果它是一个复杂的软件,其中安全性比性能更重要,那么更安全的替代方案可能会更好。
答案 3 :(得分:0)
原始指针的问题在于无法判断它是否仍指向有效对象。幸运的是,std::shared_ptr
有一个aliasing constructor可用于有效地为具有自动存储持续时间的类成员创建std::weak_ptr
。例如:
#include <iostream>
#include <memory>
using namespace std;
struct A {
int x;
};
void PrintValue(weak_ptr<int> wp) {
if (auto sp = wp.lock())
cout << *sp << endl;
else
cout << "Object is expired." << endl;
}
int main() {
shared_ptr<A> a(new A);
a->x = 42;
weak_ptr<int> wpInt (shared_ptr<int>(a, &a->x));
PrintValue(wpInt);
a.reset(); //a->x has been destroyed, wpInt no longer points to a valid int
PrintValue(wpInt);
return 0;
}
打印:
42
对象已过期。
这种方法的主要好处是weak_ptr
不会阻止对象超出范围并被删除,但同时它可以安全地检测对象何时不再有效。缺点是智能指针的开销增加,以及最终需要shared_ptr
到对象的事实。即你不能专门用堆栈上分配的对象来做这件事。
答案 4 :(得分:-3)
简单地动态分配对象并使用shared_ptr
。是的,它实际上会删除该东西,但前提是它是带引用的最后一个。此外,它也可以防止他人删除它。这是正确的做法,既可以避免内存泄漏,也可以避免悬空指针。另请查看相关的weap_ptr
,如果指针对象的生命周期要求不同,您也可以使用它们。