C++ 指向没有所有权的堆栈对象的指针

C++ 指向没有所有权的堆栈对象的指针,c++,pointers,c++11,smart-pointers,C++,Pointers,C++11,Smart Pointers,我想要一个带有指针成员变量的类。该指针应该指向一个对象,该对象可以是堆栈分配的,也可以是堆分配的。但是,此指针不应具有任何所有权。换句话说,当指针超出范围时,不应该调用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智能指针。有人建议为非自有对象使用“愚蠢”智能指针:

已经通过实验实现为(感谢@T.C.的提示)

另一种选择是将智能指针与不执行任何操作的自定义删除器一起使用:

#include <memory>

int main()
{
    int a{42};

    auto no_op = [](int*){};
    std::unique_ptr<int, decltype(no_op)> up(&a, no_op);
}
#包括
int main()
{
int a{42};
自动无运算=[](int*){};
std::唯一的ptr up(&a,无操作);
}
或者,正如@T.C.在评论中提到的,a


正如@Lightness Races in Orbit所提到的,a也可能是一个解决方案,因为后者也是一个非自有智能指针。但是,
std::weak_ptr
只能从一个或另一个
std::weak_ptr
构建。一个严重的缺点是,
std::shared_ptr
是一个“重”对象(因为内部引用计数机制)。请注意,即使在这种情况下,
std::shared_ptr
也必须有一个简单的自定义删除程序,否则它会破坏指向自动变量指针的堆栈。

只需动态分配对象并使用
shared_ptr
。是的,它实际上会删除该对象,但前提是它是最后一个带有引用的对象。此外,它还防止其他人删除它。这正是正确的做法,既可以避免内存泄漏,也可以避免指针悬空。还可以查看相关的
weap\u ptr
,如果指针对象的生命周期要求不同,您也可以使用它来发挥自己的优势。

如果“更好的方法”是指“更安全的方法”,那么是的,我在这里实现了一个“非拥有”智能指针:。(无耻的插件警报,但我认为它与此相关。)因此您的代码如下所示:

#include "mseregistered.h"
...

class foo{
public:
    mse::TRegisteredPointer<bar> pntr;
};

int main(){
    mse::TRegisteredObj<bar> a;
    foo b;
    b.pntr=&a;
}
#包括“mseregistered.h”
...
福班{
公众:
mse::注册点pntr;
};
int main(){
mse::TRegisteredObj a;
富b;
b、 pntr=&a;
}
TRegisteredPointer比原始指针“更聪明”,因为它知道目标何时被摧毁。例如:

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. 
    };
}
intmain(){
富b;
c栏;
{
mse::TRegisteredObj a;
b、 pntr=&a;
c=*(b.pntr);
}
试一试{
c=*(b.pntr);
}捕获(…){
//b.pntr“知道”它指向的对象已被删除,因此它引发异常。
};
}
TRegisteredPointer通常比std::shared\u ptr具有更低的性能成本。当您有机会在堆栈上分配目标对象时,成本会低很多。虽然它还是相当新的,并且还没有很好的文档记录,但是这个库包含了它使用的注释示例(在文件“msetl_example.cpp”的下半部分)

该库还提供了TRegisteredPointerForLegacy,这比TRegisteredPointer稍慢一些,但在几乎任何情况下都可以作为原始指针的替代品。(特别是,它可以在完全定义目标类型之前使用,而TRegisteredPointer的情况并非如此。)


就你问题的情绪而言,我认为这是正确的。现在C++程序员至少应该有选择避免不必要的内存访问风险。原始指针也可以是一个有效的选项,但我认为它取决于上下文。如果它是一个复杂的软件,安全性比性能更重要,那么更安全的替代方案可能更好。

原始指针的问题是无法判断它是否仍然指向有效的对象。幸运的是,
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;
}
#包括
#包括
使用名称空间std;
结构A{
int x;
};
无效打印值(弱ptr wp){
如果(auto sp=wp.lock())

你真的应该链接到,或者。另外,如果指针不应该为空,
reference\u wrapper
是一个选项。@vsoftco:谢谢。我一开始有一个不同的笑话,但它是垃圾,所以我
删除它。@vsoftco:太好了。谢谢你忍受我的
笑话。@lightnessraceinorbit甚至
笑话可以
共享
@Voo,例如,你(或你图书馆的客户)不会错误地删除它。从某种意义上说,你清楚地表明指针是非所有权的。我链接的论文摘要提到:“因此,它几乎可以替代原始指针类型,其优点是,作为词汇表类型,它表明了它的预期用途,而无需代码读者进行详细分析“这是不对的。如果指针是自动变量,那么你就结束了堆栈。好的,我不清楚这一部分。我建议在任何情况下阅读指令,以避免常见的陷阱。我同意这一部分的概念(Urlich和其他):C++内存模型太多。(对于大型应用程序,通用计算),同意这种“过度设计”(某种类型)可以减少,例如使用静态/分配的/etc智能指针中的分配数据部分。相反,低硬件项目需要使用更激进的代码。顺便说一句,在许多uC上,堆栈是高度有限的资源