auto_ptr设计

时间:2009-01-15 02:48:42

标签: c++

在我看来,一个类应该提供一个定义明确的抽象,并且在没有类知识的情况下不应该修改私有成员。但是当我检查“auto_ptr”(或任何其他智能指针)时,违反了此规则。请参阅以下代码

class Foo{
public:
   Foo(){}
};

int main(int argc, char* argv[])
{
   std::auto_ptr<Foo> fooPtr(new Foo);
   delete fooPtr.operator ->();
   return 0;
}

运算符重载( - &gt;)给出了底层指针,可以在不知道“auto_ptr”的情况下修改它。我不能认为它是一个糟糕的设计,因为智能指针是由C ++极客设计的,但我想知道为什么他们允许这个。有没有办法在没有这个问题的情况下编写智能指针。

欣赏你的想法。

6 个答案:

答案 0 :(得分:5)

智能指针应该有两个理想的属性:

  1. 可以检索原始指针(例如,用于传递到旧库函数)
  2. 无法检索原始指针(以防止双重删除)
  3. 显然,这些属性是矛盾的,无法同时实现!甚至Boost的shared_ptr<Foo>等。有get(),所以他们有这个“问题”。在实践中,第一个更重要,所以第二个必须去。

    顺便说一句,当普通的旧operator->()方法导致同样的问题时,我不确定为什么你会找到略显模糊的get()

    std::auto_ptr<Foo> fooPtr(new Foo);
    delete fooPtr.get();
    

答案 1 :(得分:4)

为了提供对底层对象的快速,方便,“指针式”访问,operator-&gt;不幸的是,它必须“泄漏”它的抽象。否则,智能指针必须手动包装允许公开的所有成员。这些要么需要在实例化智能指针的那些部分上进行大量的“配置”工作,要么在C ++中不存在的元编程水平。此外,正如pyrsta指出的那样,即使这个漏洞被插入,仍有许多其他(可能是非标准的)方法来破坏C ++的访问控制机制。

答案 2 :(得分:2)

不,没有办法完全禁止在C ++中使用这种错误。

作为一般规则,除非特别记录,否则任何库代码的用户都不应该对任何包装指针调用delete。在我看来,应该设计所有现代C ++代码,以便类的用户永远不会完全负责手动释放她获得的资源(即使用RAII代替)。

除了注意:std::auto_ptr<T>不再是最佳选择。它在复制时的不良行为可能导致严重的编码错误。通常,更好的方法是使用std::tr1::scoped_ptr<T>std::tr1::shared_ptr<T>或其Boost变体。

此外,在C ++ 0x中,std::unique_ptr<T>将在函数上取代std::auto_ptr<T>作为更安全的类。可以找到关于该主题的一些讨论以及针对unique_ptr仿真的最新C ++ 03实现here

答案 3 :(得分:2)

  

有没有办法在没有这个问题的情况下编写智能指针。

这并不容易,而且一般都没有(也就是说,你不能为每个普通的Foo类做到这一点。)

我能想到的唯一方法就是更改Foo类的声明:将Foo析构函数设为私有(或定义私有delete运算符作为Foo类的成员),并在Foo类的声明中指定std::auto_ptr<Foo>friend

答案 4 :(得分:0)

我不认为这表明auto_ptr存在封装问题。无论何时处理自有指针,人们都必须了解谁拥有什么。在auto_ptr的情况下,它拥有它所持有的指针[1];这是auto_ptr抽象的一部分。因此,以任何其他方式删除该指针违反了auto_ptr提供的合同。

我同意误用auto_ptr [2]相对容易,这是非常不理想的,但在C ++中,你永远无法避免“谁拥有这个指针?”的基本问题,因为为了更好或者更糟糕的是,C ++不会为你管理内存。

[1]来自cplusplus.com的引用:“auto_ptr对象具有取得分配给它们的指针所有权的特殊性”:http://www.cplusplus.com/reference/std/memory/auto_ptr/

[2]例如,您可能错误地认为它具有值语义,并将其用作矢量模板参数:http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0CEEQFjAD&url=http%3A%2F%2Fwww.gamedev.net%2Ftopic%2F502150-c-why-is-stdvectorstdauto_ptrmytype--bad%2F&ei=XU1qT5i9GcnRiAKCiu20BQ&usg=AFQjCNHigbgumbMG3MTmMPla2zo4LhaE1Q&sig2=WSyJF2eWrq2aB2qw8dF3Dw

答案 5 :(得分:0)

我认为这个问题解决了一个问题。智能指针用于管理指针的所有权,如果这样做会使指针无法访问,则它们无法实现其目的。

还要考虑这一点。任何容器类型都为你提供迭代器;如果it是这样的迭代器,则&*it是指向容器中项目的指针;如果你说delete &*it那么你已经死了。但暴露其物品的地址并不是容器类型的缺陷。