In practice, the intelligent pointer unique_ptr series in c ++ -- std: unique_ptr construction (try to use std: make_unique in C ++ 14, instead of new)
The previous blog is an opening part of unique_ptr, which is to briefly explain why unique_ptr is used. Compared with traditional pointers, intelligent pointers only offer advantages.
Let's start with the construction!
Take a look at these constructor methods:
default (1) constexpr unique_ptr() noexcept;from null pointer (2) constexpr unique_ptr (nullptr_t) noexcept : unique_ptr() {}from pointer (3) explicit unique_ptr (pointer p) noexcept;from pointer + lvalue deleter (4) unique_ptr (pointer p, typename conditional
::value,D,const D&> del) noexcept;from pointer + rvalue deleter (5) unique_ptr (pointer p, typename remove_reference
::type&& del) noexcept;move (6) unique_ptr (unique_ptr&& x) noexcept;move-cast (7) template
unique_ptr (unique_ptr
&& x) noexcept;move from auto_ptr (8) template
unique_ptr (auto_ptr&& x) noexcept;copy (deleted!) (9) unique_ptr (const unique_ptr&) = delete;
The methods for constructing unique_ptr are as follows:
First look at 1 2 3 4 5 8
# Include
# Include
Int main () {std: default_delete
D; std: unique_ptr
U1; std: unique_ptr
U2 (nullptr); std: unique_ptr
U3 (new int); std: unique_ptr
U4 (new int, d); std: unique_ptr
U5 (new int, std: default_delete
(); Std: unique_ptr
U8 (std: auto_ptr
(New int); std: cout <"u1:" <(u1? "Not null": "null") <'\ n'; if (u1! = Nullptr) {std: cout <"* u1:" <* u1 <std: endl;} std: cout <"u2: "<(u2? "Not null": "null") <'\ n'; if (u2! = Nullptr) {std: cout <"* u2:" <* u2 <std: endl;} std: cout <"u3: "<(u3? "Not null": "null") <'\ n'; if (u3! = Nullptr) {std: cout <"* u3:" <* u3 <std: endl;} std: cout <"u4: "<(u4? "Not null": "null") <'\ n'; if (u4! = Nullptr) {std: cout <"* u4:" <* u4 <std: endl;} std: cout <"u5: "<(u5? "Not null": "null") <'\ n'; if (u5! = Nullptr) {std: cout <"* u5:" <* u5 <std: endl;} std: cout <"u8: "<(u8? "Not null": "null") <'\ n'; if (u8! = Nullptr) {std: cout <"* u8:" <* u8 <std: endl;} return 0;} output: u1: nullu2: nullu3: not null * u3:-842150451u4: not null * u4:-842150451u5: not null * u5:-842150451u8: not null * u8:-842150451
The analysis shows that constructor 1 2 is equivalent to nullptr, while others are junk values.
Constructor 3 is perhaps the most familiar form, such as int * p = new int;
Here the constructor 4 5 uses a std: default_delete. What is this?
Std: default_delete is the default destruction policy used by std: unique_ptr when no deleter is specified.
1) The non-specialized default_delete uses delete to deallocate memory for a single object.
2) A partial specialization for array types that uses delete [] is also provided.
Constructor 8 constructs unique_ptr from other smart pointers.
The following are the six and seven constructor methods that use the std: move syntax. We will add and demonstrate the following:
# Include
# Include
Int main () {std: default_delete
D; std: unique_ptr
U1; std: unique_ptr
U2 (nullptr); std: unique_ptr
U3 (new int); std: unique_ptr
U4 (new int, d); std: unique_ptr
U5 (new int, std: default_delete
(); Std: unique_ptr
U8 (std: auto_ptr
(New int); std: cout <"u1:" <(u1? "Not null": "null") <'\ n'; if (u1! = Nullptr) {std: cout <"* u1:" <* u1 <std: endl;} std: cout <"u2: "<(u2? "Not null": "null") <'\ n'; if (u2! = Nullptr) {std: cout <"* u2:" <* u2 <std: endl;} std: cout <"u3: "<(u3? "Not null": "null") <'\ n'; if (u3! = Nullptr) {std: cout <"* u3:" <* u3 <std: endl;} std: cout <"u4: "<(u4? "Not null": "null") <'\ n'; if (u4! = Nullptr) {std: cout <"* u4:" <* u4 <std: endl;} std: cout <"u5: "<(u5? "Not null": "null") <'\ n'; if (u5! = Nullptr) {std: cout <"* u5:" <* u5 <std: endl;} std: cout <"u8: "<(u8? "Not null": "null") <'\ n'; if (u8! = Nullptr) {std: cout <"* u8:" <* u8 <std: endl;} std: unique_ptr
U6 (std: move (u5); std: cout <"u6:" <(u6? "Not null": "null") <'\ n'; if (u6! = Nullptr) {std: cout <"* u6:" <* u6 <std: endl;} std: cout <"now, let us see u5: "; std: cout <" u5: "<(u5? "Not null": "null") <'\ n'; if (u5! = Nullptr) {std: cout <"* u5:" <* u5 <std: endl;} std: unique_ptr
U7 (std: move (u6); std: cout <"u7:" <(u7? "Not null": "null") <'\ n'; if (u7! = Nullptr) {std: cout <"* u7:" <* u7 <std: endl;} std: cout <"now, let us see u6: "; std: cout <" u6: "<(u6? "Not null": "null") <'\ n'; if (u6! = Nullptr) {std: cout <"* u6:" <* u6 <std: endl;} return 0 ;}// output: // u1: null // u2: null // u3: not null // * u3:-842150451 // u4: not null // * u4:-842150451 // u5: not null // * u5:-842150451 // u8: not null // * u8:-842150451 // u6: not null // * u6:-842150451 // now, let us see u5: u5: null // u7: not null // * u7:-842150451 // now, let us see u6: u6: null
The most important thing to note here is:
U5 was not null, but after std: move, u5 becomes null,
U6 is not empty at the beginning. After std: move, u6 is also empty.
It also needs to be emphasized that, when removing the pointer from the reference, it is necessary to verify whether the pointer is null. if the pointer is null and then the value operation is performed, the program will crash. Serious bug.
If I write it now, I will stop. You will say that I am a title party, but I am not.
Continue:
Std: make_unique is not included in c ++ 11, which is the content of C ++ 14:
There are three constructors:
Template <class T, class... Args>
Unique_ptr make_unique (Args &&... Args );
Template <class T>
Unique_ptr make_unique (std: size_t size );
Template <class T, class... Args>
/* Unspecified */make_unique (Args &&... Args) = delete;
# Include
# Include
Struct Vec3 {int x, y, z; Vec3 (): x (0), y (0), z (0) {} Vec3 (int x, int y, int z): x (x), y (y), z (z) {} friend std: ostream & operator <(std: ostream & OS, vec3 & v) {return OS <'{' <"x:" <v. x <"y:" <v. y <"z:" <v. z <'}' ;}}; int main () {// Use the default constructor. std: unique_ptr
V1 = std: make_unique
(); // Use the constructor that matches these arguments std: unique_ptr
V2 = std: make_unique
(0, 1, 2); // Create a unique_ptr to an array of 5 elements std: unique_ptr
V3 = std: make_unique
(5); std: cout <"make_unique
(): "<* V1 <'\ n' <" make_unique
(0, 1, 2): "<* v2 <'\ n' <" make_unique
(5): "<'\ n'; for (int I = 0; I <5; I ++) {std :: cout <"" <v3 [I] <'\ n' ;}}// output: // make_unique
(): {X: 0 y: 0 z: 0} // make_unique
(0, 1, 2): {x: 0 y: 1 z: 2} // make_unique
(5): // {x: 0 y: 0 z: 0} // {x: 0 y: 0 z: 0} // {x: 0 y: 0 z: 0} // {x: 0 y: 0 z: 0} // {x: 0 y: 0 z: 0}
As you can see, make_unique perfectly passes the parameter to the object's constructor, constructs a std: unique from an original pointer, and returns the created std: unique_ptr. Functions in this form do not support arrays and custom delimiters.
Compared with the direct use of new, the make function reduces code duplication and improves exception security. For std: make_shared and std: allcoated_shared, the generated code is smaller and faster.
At this point, you can refer to the blog http://blog.csdn.net/coolmeme/article/details/43405155