确保指针不会被删除

时间:2009-11-10 11:30:21

标签: c++ pointers

我偶然发现了一些我无法弄清楚的东西,所以我觉得我在大C ++图片中遗漏了一些东西。

简而言之,我的问题是:如何在类中保留一个可变的,不可删除的,可能是NULL的对象实例。

较长的版本是:

我有以下场景:一堆类(我可以略微改变,但不是彻底的重构),其中大部分需要使用一个对象。该对象虽然可变,但由其他人管理,因此不得删除。

一些类中的一些类不需要这样的对象 - 它们重用来自其他类的代码,但是通过提供给这些类的可用参数,即使提供了对象,也不会使用它。

当前实现使用指针到const对象(const Obj *)。反过来,这意味着所有对象的方法必须是const,并且大多数字段都是可变的。这是一个混乱的解决方案,因为声明mutable的字段可供检查(因此与c ++ lite条目here完全相反)。它也只是部分地解决了“do-not-delete-this-here”问题(编译器没有抱怨,但是对象前面的const是一个指示)。

如果我使用了对这个对象的引用,我会强制一些调用者创建一个“虚拟”对象并将它提供给他们实例化的类。这也是一种混乱,除了浪费资源。由于项目限制,我无法创建一个可以代表“NULL”引用的全局对象。

我觉得引用是我需要的工具,但是我无法重构所涉及的类,以至于让对象从它们未被使用的实现中消失(可以完成,但它并不简单它不会很快)。所以我想实现一些更简单的东西,如果有人试图滥用这个对象,只会绘制一个警报信号,但保持我的对象可变。

我能想到的最好的解决方案是使用const-pointer-to-object(Obj * const) - 这不会让编译器抱怨,但是我有可变对象和一种警报信号 - 通过const - 也就位。

有没有人有更好的主意?

6 个答案:

答案 0 :(得分:6)

您可以将该对象的析构函数设为私有。这会在尝试删除对象时触发编译时错误。此外,您应该允许已恢复的代码使用朋友机制或成员函数删除对象。

答案 1 :(得分:6)

我传统上看到使用shared_ptr / weak_ptr组合实现这些场景。见here.

所有者/删除者会得到一个

boost::shared_ptr<T>

你的班级会得到一个

boost::weak_ptr<T>

要重新分配弱ptr,只需重新分配指针:

void MyClass::Reassign(boost::weak_ptr<T> tPtr)
{
    m_tPtr = tPtr;
}

要使用弱ptr,首先要检查它是否仍然存在:

void MyClass::Use()
{
    boost::shared_ptr<T> m_temporarySharedPtr = m_tPtr.lock();
    if (m_temporarySharedPtr)
    {
        //...
    }
}

可以通过重置弱ptr或将其分配给空的shared_ptr来使弱ptr为“NULL”

void MyClass::MakeNull()
{
    m_tPtr.reset();
}

答案 2 :(得分:1)

您可以在指针周围放置一个包装器以允许修改但不能删除:

template <typename T> class Wrapper
{
public:
    Wrapper(T *p=0) : pointer(p) {}

    T       *operator->()       {return pointer;}
    T const *operator->() const {return pointer;}
    operator bool()       const {return pointer;}

private:
    T *pointer;
};

您可以像在某些上下文中指向模板类型的指针一样使用它,但不能在其上调用delete。包装类型必须是structclass类型(即->有意义的类型)。然后,一个使用但不管理对象生命周期的类看起来有点像这样:

class User
{
public:
    void Assign(Object *o) {object = o;}
    void UseObject() {if (object) object->Use();}

private:
    Wrapper<Object> object;
};

从技术上讲,你仍然可以获得原始指针,但执行它的代码看起来非常错误:

delete wrapper.operator->();

答案 3 :(得分:0)

听起来像是shared_ptr的情况。

答案 4 :(得分:0)

另一种方法(如果您的restircitons允许)将创建一个类似于共享指针的虚拟对象,以充当相关对象与您的类之间的包装。

您的类可以尝试删除此对象,但它本身将保持原始对象不变。重载*运算符,您可以透明地使用它。

答案 5 :(得分:0)

这样的事情?...

Obj类是你的新类的聚合,你用Obj* cont pObj指向它,你在创建新类时设置(或者如果不使用则保留为0),然后你在调用任何函数之前检查pObj?

if ( pObj ){ pObj->foo(); }

如果函数foo被错误地定义为可变,那么你需要修复它的声明。

您的新班级不负责清理/删除Obj课程。