2009-01-15 68 views
1

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

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

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

操作过载( - >)给出下面的指针,它可以不使用“的auto_ptr”的知识进行修改。我不能认为这是一个糟糕的设计,因为智能指针是由C++极客设计的,但我想知道他们为什么允许这样做。有没有办法写出没有这个问题的智能指针。

欣赏你的想法。

+1

我想不出许多有用的类没有这样的事情。它很方便,但不要愚蠢。 `delete []&vector [0];` – 2012-03-21 22:15:01

回答

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找到。

+0

谢谢。我只是为了解释而使用auto_ptr。我正在使用boost :: shared_ptr。 RAII看起来很有趣 – 2009-01-15 03:17:35

+0

不知道为什么这个答案是downvoted ... – 2009-01-15 13:12:07

4

为了提供对基础对象的快速,方便的“指针式”访问,operator->不得不“泄漏”它的抽象。否则,智能指针将不得不手动包装允许公开的所有成员。这些实例化智能指针需要很多“配置”工作,或者C++中不存在的元编程级别。此外,正如pyrsta指出的那样,即使这个漏洞被封堵,仍然有许多其他(也许是非标准的)方式来颠覆C++的访问控制机制。

+0

这很有道理。谢谢 – 2009-01-15 03:18:12

2

有什么办法可以写出没有这个问题的智能指针。

这并不容易,一般也不会(即不能为每一个普通的Foo类做)。

我能想到的,做到这一点,是通过改变Foo类的声明的唯一方法:使Foo析构函数私人(或定义的私人delete运营商作为Foo类的成员),并且还在类别Foo的声明中指定std::auto_ptr<Foo>friend

+0

是的,这是我认为的唯一方法。但是Foo必须进行修改,并且所有将与auto_ptr一起使用的类。这将是矫枉过正。 – 2009-01-15 03:15:59

5

有两个所需特性的智能指针应具有:

  1. 原始指针可以被检索(例如传递到传统的库函数)
  2. 原始指针不能被检索(防止双删除)

显然,这些特性是矛盾的,不能在同一时间实现! Even Boost's shared_ptr<Foo> et al。有get(),所以他们有这个“问题”。在实践中,第一个更重要,所以第二个必须去。

顺便说一句,我不知道为什么你伸手稍微隐晦operator->()当普通老get()方法会导致同样的问题:

std::auto_ptr<Foo> fooPtr(new Foo); 
delete fooPtr.get(); 
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

0

我认为这个问题解决了一个非问题。智能指针用于管理指针的所有权,如果这样做会使指针不可访问,则它们失败。

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