我想要一个类,它带有一个指针成员变量。此指针应该指向一个可以在堆栈或堆上分配的对象。但是,这个指针不应该拥有任何权利。换句话说,当指针超出范围时,不应调用delete。我认为原始指针可以解决这个问题……但是,我不确定C ++ 11是否有比原始指针更好的方法?
class foo{
public:
bar* pntr
};
int main(){
bar a;
foo b;
b.pntr=&a;
}
我想要一个类,它带有一个指针成员变量。此指针应该指向一个可以在堆栈或堆上分配的对象。但是,这个指针不应该拥有任何权利。换句话说,当指针超出范围时,不应调用delete。我认为原始指针可以解决这个问题……但是,我不确定C ++ 11是否有比原始指针更好的方法?
class foo{
public:
bar* pntr
};
int main(){
bar a;
foo b;
b.pntr=&a;
}
在这里使用原始指针是完全可以的。C++11没有任何其他处理非拥有对象的“愚蠢”智能指针,因此您不能使用C++11智能指针。有一个提案用于非拥有对象的“愚蠢”智能指针:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4282.pdf
已经实验性地实现为 std::experimental::observer_ptr
(感谢 @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::reference_wrapper
。
正如@Lightness Races in Orbit所提到的,std::weak_ptr
也可能是一种解决方案,因为后者也是一种非拥有智能指针。然而,std::weak_ptr
只能从std::shared_ptr
或另一个std::weak_ptr
构造。一个严重的缺点是std::shared_ptr
是一个“重量级”对象(因为内部引用计数机制)。请注意,即使在这种情况下,std::shared_ptr
必须具有平凡的自定义删除器,否则它会破坏指向自动变量的指针的堆栈。
std::shared_ptr
有一个别名构造函数,你可以使用它来有效地创建一个具有自动存储期的类成员的 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
。也就是说,您不能完全使用在堆栈上分配的对象来实现此目的。
#include "mseregistered.h"
...
class foo{
public:
mse::TRegisteredPointer<bar> pntr;
};
int main(){
mse::TRegisteredObj<bar> a;
foo b;
b.pntr=&a;
}
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具有更低的性能成本。当您有机会在堆栈上分配目标对象时,性能成本会更低。虽然它仍然相对较新且文档不太完善,但该库包括其使用的注释示例(在文件“msetl_example.cpp”的下半部分)。
该库还提供了TRegisteredPointerForLegacy,它比TRegisteredPointer略慢,但几乎可以在任何情况下用作原始指针的替代品。(特别是在目标类型完全定义之前可以使用它,而这不是TRegisteredPointer的情况。)
就您的问题的情感而言,我认为它是有效的。到现在为止,C++程序员应该至少有避免无效内存访问风险的选择。原始指针也可能是一个有效的选择,但我认为这取决于上下文。如果它是一种复杂的软件,在其中安全性比性能更重要,则更安全的替代方案可能更好。
只需动态分配对象并使用shared_ptr
即可。是的,它实际上会删除该对象,但仅当它是具有引用的最后一个对象时才会删除。此外,它还可以防止其他人删除它。这正是正确的做法,既避免了内存泄漏,也避免了悬空指针。还要查看相关的weap_ptr
,如果指向物的生命周期要求不同,您也可以利用它。
删除
了。 - Lightness Races in Orbit