Where's the proper (resource handling) Rule of Zero? [closed]

好久不见. 提交于 2019-12-29 07:33:08

问题


Here's an article that talks about an idiom named Rule of Zero.

Here's an excerpt:

class module {
public:
    explicit module(std::wstring const& name)
    : handle { ::LoadLibrary(name.c_str()), &::FreeLibrary } {}

    // other module related functions go here

private:
    using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;

    module_handle handle;
};

It reuses unique_ptr RAII features so you don't need to care about implementing a daunting and verbose Rule of Five wrapper.

Presented this way (managing handle based resources with unique_ptr, that way), it looks as a hack for me, not a best solution for what it's trying to solve. Too many assumptions are being implicitly assumed:

  • One is able to peer and use the basic type the #define (or typedef) HANDLE is built upon. For me this should be hidden knowledge, and a solution be based exclusively on what the interface makes available: HANDLE.
  • Handles, can be anything, they're not required to be pointer types.

I'd like to use this idiom, but it falls short in many situations I stumble upon.

Is this handle focused RAII wrapper already done and usable in some cool library? Is everybody using such a tool and I'm not aware? (I think it nice to have such tooling not only for one, but for the many types of ownerships that are)

EDIT 1

This is not about platform specific resource handles, e.g., glGenLists returns a kind of handle, it's a GLuint, and you should call glDeleteLists on it. As already stated, resource handles are not required to be pointer types, and this assumption should not be assumed.

EDIT 2

Rule of Zero, in the former sample, by employing an already existing tool, unique_ptr, shows as a nice shortcut for handle management. The extra assumptions that it requires makes it falls short. The right assumptions are that you have a handle and you have a resource destroying function that destroys the resource given by the handle. Whether the handle is a void *, a GLuint, whatever, it should not matter, and worse, one should not even be required to peer HANDLE inner type. For the purpose of managing handles RAII way, if the idiom tells it's good for that, and can't apply in such situations, I feel it's not good for that, at last with the given tool.

EDIT 3

An illustrative situation would be, let's say you're in charge of using a fresh 3rd party C library. It contains a FooHandle create_foo() and a void destroy_foo(FooHandle). So you think, "let's use FooHandle's by employing the Rule of Zero". Ok, you go by using a unique_ptr, a unique_ptr to what you ask yourself? Is FooHandle a pointer?, so that you use a unique_ptr to FooHandle's not exposed basic type? Is it an int?, so that you may use it straight, or is it better to (re)typedef things like @NicolBolas has done in his answer. For me, it seems clear, even in such a trivial situation, unique_ptr is already showing as not an ideal fit for managing resource handles.

Disclaimer:

I've tried to reformulate and better express myself in:

  • Is there a proper 'ownership-in-a-package' for 'handles' available?

EDIT 4

I've found what I was looking for, I've put it as an answer in the reformulated question: https://stackoverflow.com/a/14902921.


回答1:


Background: Rule Of Zero

First and foremost, that article is about a much more general idea than just a the resource handle wrapper example it mentions.

The point is that whenever a class contains members with 'non-trivial' ownership semantics, the class should not be responsible for the mechanics of ensuring proper value semantics (copy. assign, move, destruct) of the containing class. Rather, each constituent should itself implement 'Rule-Of-3+' as appropriate, so that the composite class can leverage the compiler-defaulted special members.

Further more, the new standard smart pointer types greatly simplify the task of making this happen for the contained types. In most cases the members that required attention would be pointers: std::unique_ptr, shared_ptr, weak_ptr address the needs here.

For custom resource types you might have to write a Rule-Of-3+ wrapper class, but only once. And the rest of your classes will benefit from the Rule-Of-Zero.


The bullets:

  • One is able to peer and use the base type the #define (or typedef) HANDLE is built upon. For me this should be hidden knowledge, and a solution be based exclusively on what the interface makes available, HANDLE.

A: 90% of the time you can (and should) use std::unique_ptr<> with a custom deleter. The knowledge and responsibility for cleanup are still with the allocator. The way it should.

In the remaining cases, you'll have to write a single wrapper class for your specific resource that isn't otherwise supported.

  • Handles, can be anything, they're not required to be pointer types.

They can. You'd look at e.g. boost::optional. Or write that wrapper. The point is, you want it isolated for the resource. You don't want to complicate a class that happens to own/contain such a resource.




回答2:


Is this handle focused RAII wrapper already done and usable in some cool library?

For your case, it's called unique_ptr. Observe:

struct WndLibDeleter
{
  typedef HANDLE pointer;

  void operator()(HANDLE h) {::FreeLibrary(h);}
};

using WndLibrary = std::unique_ptr<HANDLE, WndLibDeleter>;

WndLibrary LoadWndLibrary(std::wstring const& name)
{
  return WndLibrary(::LoadLibrary(name.c_str()));
}

With deleters, unique_ptr can service store and service any kind of object that is NullablePointer. HANDLE is a NullablePointer, so you can service it.

For objects that aren't NullablePointers, you'll have to use something else. The point of the Rule of Zero is to make "something else" as small as possible. It would be nothing more than a RAII-wrapper around the type, providing nothing more than access to it and move support. Therefore, the vast majority of your code does not need explicit copy/move constructors; just those few leaf classes.



来源:https://stackoverflow.com/questions/14865919/wheres-the-proper-resource-handling-rule-of-zero

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!