重新审视智能指针上没有隐式转换的原因

时间:2015-11-02 10:38:32

标签: c++ pointers smart-pointers unique-ptr

[一个答案,下面是强制选择.release().get(),遗憾的是,错误的一般建议只是使用.get()]

摘要:这个问题是出于技术原因或行为原因(可能基于经验),为什么智能指针(如unique_ptr)被剥夺了指针的主要特征, 在预期指针的位置传递的能力(C API' s)。

我已经研究了这个主题并引用了下面两个主要的声明原因,但这些原因似乎无效。

但是我的傲慢并不是无限的,而且我的经历并不那么广泛,以至于让我相信我一定是对的。

unique_ptr可能不是设计简单的dumb C API指针的生命周期管理作为主要用途,当然这个unique_ptr的拟议开发不会是[http://bartoszmilewski.com/2009/05/21/unique_ptr-how-unique-is-it/],但{ {1}}声称是" auto_ptr应该是什么" (但我们无法用C ++ 98编写)" [http://www.stroustrup.com/C++11FAQ.html#std-unique_ptr]但也许这不是auto_ptr的主要用途。

我使用unique_ptr来管理某些C API资源,并震惊[是的,震惊的:-)],发现所谓的智能指针根本就​​不像指针一样。

我使用的API预期指针,我真的不希望在整个地方添加unique_ptr。这一切都使智能指针.get()显得相当愚蠢。

unique_ptr 当前的推理是什么,当unique_ptr被投射到该指针的类型时,它不会自动转换为它所持有的指针?

void do_something(BLOB* b);
unique_ptr<BLOB> b(new_BLOB(20));

do_something(b); 
// equivalent to do_something(b.get()) because of implicit cast

我已阅读http://herbsutter.com/2012/06/21/reader-qa-why-dont-modern-smart-pointers-implicitly-convert-to/,并且非常明确(鉴于作者)并没有令人信服地回答这个问题,所以我想知道是否有更多真实的例子或技术/行为方面的理由来证明这一点。

要参考文章示例,我没有尝试do_something(b + 42),并且我没有在我指向的对象上定义+,因此*b + 42没有&#39}有意义。

但如果确实如此,如果我的意思是,那么我实际上会输入*b + 42,如果我想在指针上添加42,我会输入b + 42因为我期待我的智能指针实际上像指针一样。

让智能指针变得愚蠢的原因是,C ++程序员能够理解如何使用指针,还是会忘记尊重指针?如果我使用智能指针发出错误,它将静默编译并运行,就像使用哑指针一样? [当然这个论点没有结束,我可能会忘记>]中的->

对于帖子中的其他内容,我写delete b的可能性不大于delete b.get(),尽管这似乎是一个常见的提议理由(也许是因为遗留代码转换),并讨论了C++ "smart pointer" template that auto-converts to bare pointer but can't be explicitly deleted然而http://www.informit.com/articles/article.aspx?p=31529&seqNum=7中提到的Meyers模棱两可似乎通过为void*T*定义一个演员来回答这种情况。这样delete就可以解决使用哪种演员表。

delete问题似乎已经具有一定的合法性,因为在移植一些遗留代码时它可能是一个真正的问题,但它甚至在Meyer之前似乎得到了很好的解决( http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/sp_techniques.html#preventing_delete

是否有更多技术可以否认智能指针的这种基本指针行为?或者那些原因在当时看起来非常引人注目?

之前的讨论包含对不良内容[Add implicit conversion from unique_ptr<T> to T*Why doesn't `unique_ptr<QByteArray>` degrade to `QByteArray*`?C++ "smart pointer" template that auto-converts to bare pointer but can't be explicitly deletedhttp://bartoszmilewski.com/2009/05/21/unique_ptr-how-unique-is-it/]的一般警告,但没有具体内容,或者比使用非智能内容更糟糕指向C API的C指针。

针对编码人员盲目地添加.get()无处不在的风险以及他们应该受到保护的所有相同的伤害所带来的不便使得整个限制看起来非常不值得。

就我而言,我使用了Meyer的两个演员的伎俩,并承担了隐藏的风险,希望读者能帮助我了解它们是什么。

template<typename T, typename D, D F>
class unique_dptr : public std::unique_ptr<T, D> {
    public: unique_dptr(T* t) : std::unique_ptr<T, D>(t, F) { };
    operator T*() { return this->get(); }
    operator void*() { return this->get(); }
};

#define d_type(__f__) decltype(&__f__), __f__

感谢@Yakk的宏观提示(Clean implementation of function template taking function pointerHow to fix error refactoring decltype inside template

using RIP_ptr = unique_dptr<RIP, d_type(::RIP_free)>;
RIP_ptr rip1(RIP_new_bitmap("/tmp/test.png"));

不,这是我可以使用的智能指针。 *我在定义智能指针类型时声明free函数一次 *我可以像指针一样传递它 *当示波器死亡时它被释放

是的,我可以错误地使用API​​并泄漏自己的引用,但是.get()并没有阻止它,尽管它带来了不便。

也许我应该有一些const作为对缺乏所有权转移的点头。

1 个答案:

答案 0 :(得分:3)

unique_ptr::release [http://en.cppreference.com/w/cpp/memory/unique_ptr/release]

的文档中暗示了我在搜索中找不到的一个答案。

release()返回指针,unique_ptr然后引用nullptr,因此很明显,这可以用于将拥有的引用传递给不支持的& #39; t使用智能指针。

通过推理,get()是传递无主参考的相应函数

作为一对,这些功能解释了为什么不允许自动解除引用的原因;编码器被迫用.release().get()替换每个指针使用 ,具体取决于被调用函数如何处理指针。

因此编码人员被迫采取智能行动并选择一种行为,并将遗留代码升级为更加明确和安全。

.get()是一个奇怪的名称,但这个解释对我来说很有意义。

可悲的是,如果编码人员唯一的建议是使用.get(),那么这种策略是无效的;编码器不知道选择并且错过了使他的代码安全和清晰的机会。