Trouble understanding the C++11 syntax in the Rule of Zero
I am studying the Rule of Zero and have 2 questions for the final piece of code which demonstrates the rule.
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;
};
Why a curly bracket usage instead of parentheses to initialize handle?
It's uniform initializing method introduced in C++11
What does using module_handle = std::unique_ptr; mean exactly in this context? would it be possible to replace it with a typedef?
It's template aliasing and also for creating new type. using
is a new and powerful replacement of typedef
explicit module(std::wstring const& name)
: handle { ::LoadLibrary(name.c_str()), &::FreeLibrary }
1) This is the new (uniform) initializer-list syntax for C++11. It is passing 2 arguments to the construct function which will initialize the variable handle
. In this case, it is effectively the same as
explicit module(std::wstring const& name)
: handle(::LoadLibrary(name.c_str()), &::FreeLibrary)
Which will call the std::unique_ptr
's constructor that takes a "pointer" (in this case a handle) and a deleter (the address of FreeLibrary
).
using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;
2) This is basically the same thing as a typedef. For more information, see this.
Others have said what the curly braces are (uniform initialization) but no one explained why one might use it here when parentheses ought to work just as well.
The idea is that rather than learn all the different initialization syntaxes, C++11 enables one to simply learn one syntax and use it everywhere; Uniform initialization is one of the features added with the intent of making it easier to learn to write C++ (among other reasons).
One thing to note is that uniform initialization is uniform in the sense that it works in all initialization contexts and can do different kinds of initialization (eg, aggregate initialization vs. using a constructor), but that does not mean that any initialization can be done using it; Specifically there are a few corner cases where types can be defined such that uniform initialization won't be able to access certain constructors. The answer to this is that one simply shouldn't write such constructors. Unfortunately some are already built in to the standard library, vector<int>(4, 5)
vs. vector<int>{4, 5}
being the common example.
2. What does using module_handle = std::unique_ptr; mean exactly in this context? would it be possible to replace it with a typedef?
This is simply a different syntax for a typedef. The syntax is more powerful than a typedef because it can be templated, however that's not being used in this case. This example could be implemented using a typedef.
The reason to prefer the new syntax is because it is a more type-centric, C++-like syntax.
The old typedef syntax uses (and suffers from, according to many) the "Declaration mimics use" rule of of C; That is, using a pointer looks like *ptr
, therefore declaring a pointer uses that same expression, int *ptr;
. Using a function that returns a pointer to a function looks like (*foo())()
so declaring one again uses that same expression, int (*foo())();
. This syntax is expression-centric, where you write out an expression and the language deduces the implied type of the variable.
The problem with this syntax is that it confuses many people, and over time both C and C++ have been changed in various ways inconsistent with this original ideal. For example declaring a function in C originally followed this rule closely; In earlier versions of C you could declare a function with int foo(x, y)
which exactly mimics a function call expression foo(x, y)
. Later it became clear that type safety and checking were important and in ISO C declaring a function looks like int foo(int x, int y)
, which does not so closely mimic the function's usage.
C++ went further, for example introducing references. Since reference usages don't look any different from using regular objects there's no syntax that could be added to the declaration to follow 'declaration mimics use'. Instead they just decided not to follow the rule and simply chose syntax that wouldn't collide with it.
C++ also places a much greater emphasis on types than C does; templates which are parameterized by type, type based overloading, etc.
So both because the old syntax seems to be innately problematic and because C++ places more importance on types over expressions, C++11 introduces this new syntax for type aliases. Instead of an obscure syntax it's a straightforward using <type alias> = <type>;
. No 'spiral rule' or 'right to left' rule needed.
This syntax not only can completely replace typedefs, it also adds the ability to be directly templated, replacing the old typedef inside a template class hack that has long been needed. Again, the new syntax is an added feature that makes it easier to learn to write C++.
链接地址: http://www.djcxy.com/p/78652.html上一篇: 正确的方式来定义类型(typedef vs #define)
下一篇: 无法理解零规则中的C ++ 11语法