为什么 std::make_unique 需要初始化成员 std::unique 数组,以及如何解决 C++11 问题?
Why is std::make_unique necessary to initialize member std::unique array, and how to work around for C++11?
在下面的代码中,为什么std::make_unique
需要初始化Foo::up_
?
具体来说,为什么不使用 new Bar(...)
初始化 Foo::up_
—— 正如在注释掉的代码中那样 —— 工作?
#include <iostream>
#include <memory>
enum E {
Y = 0,
Z = 1,
NUM_E
};
class Bar {
public: // Functions
Bar( const int& i, const int& j ) : i_(i), j_(j) { }
public: // Objects
int i_;
int j_;
};
class Foo {
public: // Functions
Foo();
void reset( const int& Yi, const int& Yj,
const int& Zi, const int& Zj );
public: // Objects
std::unique_ptr<Bar> up_[NUM_E];
};
Foo::Foo()
: up_{ std::make_unique<Bar>( 42, 43 ),
std::make_unique<Bar>( 44, 45 ) }
// : up_{ new Bar( 42, 43 ),
// new Bar( 44, 45 ) } // err: could not convert from Bar* to unique_ptr
{ }
void Foo::reset( const int& Yi, const int& Yj,
const int& Zi, const int& Zj ) {
up_[Y].reset( new Bar( Yi, Yj ) );
up_[Z].reset( new Bar( Zi, Zj ) );
}
int main( int argc, char* argv[] ) {
(void)argc;
(void)argv;
Foo foo;
std::cout << foo.up_[Y]->i_ << std::endl;
std::cout << foo.up_[Y]->j_ << std::endl;
std::cout << foo.up_[Z]->i_ << std::endl;
std::cout << foo.up_[Z]->j_ << std::endl;
foo.reset( 1, 2, 3, 4 );
std::cout << foo.up_[Y]->i_ << std::endl;
std::cout << foo.up_[Y]->j_ << std::endl;
std::cout << foo.up_[Z]->i_ << std::endl;
std::cout << foo.up_[Z]->j_ << std::endl;
return 0;
}
$ g++ --version && g++ --std=c++14 ./main.cpp && ./a.out
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
42
43
44
45
1
2
3
4
C++11
如何解决此问题,其中 std::make_unique
似乎不可用?
$ g++ --version && g++ --std=c++11 ./main.cpp && ./a.out
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
./main.cpp: In constructor ‘Foo::Foo()’:
./main.cpp:31:10: error: ‘make_unique’ is not a member of ‘std’
: up_{ std::make_unique<Bar>( 42, 43 ),
^~~
./main.cpp:31:30: error: expected primary-expression before ‘>’ token
: up_{ std::make_unique<Bar>( 42, 43 ),
^
./main.cpp:32:10: error: ‘make_unique’ is not a member of ‘std’
std::make_unique<Bar>( 44, 45 ) }
^~~
./main.cpp:32:30: error: expected primary-expression before ‘>’ token
std::make_unique<Bar>( 44, 45 ) }
^
如果你没有make_unique,你可以像这样使用unique_ptr的构造函数
Foo::Foo()
: up_{ std::unique_ptr<Bar>(new Bar( 42, 43 )),
std::unique_ptr<Bar>(new Bar( 44, 45 )) }
{ }
1。构造函数 unique_ptr( pointer p )
被标记为 explicit
,这可以防止 unique_ptr
的实例在数组列表初始化时被隐式构造。
2。 std::make_unique
自 C++14 起可用。
在 C++11 中,对这两点的一个可能解决方案是显式构造一个实例,例如std::unique_ptr<Bar>(new Bar( 42, 43 ))
.
您不能从简单指针的数组初始值设定项构造 unique_ptr's
数组的原因是因为 unique_ptr
指针构造函数是 explicit.
要解决此问题,您可以调用 unique_ptr
的显式构造函数,但这很无聊并且容易出现问题,导致首先添加 make_unique
。相反,您可以简单地拥有自己的 compat::make_unique
模板函数,它实际上是 1 行:
template<class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
在下面的代码中,为什么std::make_unique
需要初始化Foo::up_
?
具体来说,为什么不使用 new Bar(...)
初始化 Foo::up_
—— 正如在注释掉的代码中那样 —— 工作?
#include <iostream>
#include <memory>
enum E {
Y = 0,
Z = 1,
NUM_E
};
class Bar {
public: // Functions
Bar( const int& i, const int& j ) : i_(i), j_(j) { }
public: // Objects
int i_;
int j_;
};
class Foo {
public: // Functions
Foo();
void reset( const int& Yi, const int& Yj,
const int& Zi, const int& Zj );
public: // Objects
std::unique_ptr<Bar> up_[NUM_E];
};
Foo::Foo()
: up_{ std::make_unique<Bar>( 42, 43 ),
std::make_unique<Bar>( 44, 45 ) }
// : up_{ new Bar( 42, 43 ),
// new Bar( 44, 45 ) } // err: could not convert from Bar* to unique_ptr
{ }
void Foo::reset( const int& Yi, const int& Yj,
const int& Zi, const int& Zj ) {
up_[Y].reset( new Bar( Yi, Yj ) );
up_[Z].reset( new Bar( Zi, Zj ) );
}
int main( int argc, char* argv[] ) {
(void)argc;
(void)argv;
Foo foo;
std::cout << foo.up_[Y]->i_ << std::endl;
std::cout << foo.up_[Y]->j_ << std::endl;
std::cout << foo.up_[Z]->i_ << std::endl;
std::cout << foo.up_[Z]->j_ << std::endl;
foo.reset( 1, 2, 3, 4 );
std::cout << foo.up_[Y]->i_ << std::endl;
std::cout << foo.up_[Y]->j_ << std::endl;
std::cout << foo.up_[Z]->i_ << std::endl;
std::cout << foo.up_[Z]->j_ << std::endl;
return 0;
}
$ g++ --version && g++ --std=c++14 ./main.cpp && ./a.out
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
42
43
44
45
1
2
3
4
C++11
如何解决此问题,其中 std::make_unique
似乎不可用?
$ g++ --version && g++ --std=c++11 ./main.cpp && ./a.out
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
./main.cpp: In constructor ‘Foo::Foo()’:
./main.cpp:31:10: error: ‘make_unique’ is not a member of ‘std’
: up_{ std::make_unique<Bar>( 42, 43 ),
^~~
./main.cpp:31:30: error: expected primary-expression before ‘>’ token
: up_{ std::make_unique<Bar>( 42, 43 ),
^
./main.cpp:32:10: error: ‘make_unique’ is not a member of ‘std’
std::make_unique<Bar>( 44, 45 ) }
^~~
./main.cpp:32:30: error: expected primary-expression before ‘>’ token
std::make_unique<Bar>( 44, 45 ) }
^
如果你没有make_unique,你可以像这样使用unique_ptr的构造函数
Foo::Foo()
: up_{ std::unique_ptr<Bar>(new Bar( 42, 43 )),
std::unique_ptr<Bar>(new Bar( 44, 45 )) }
{ }
1。构造函数 unique_ptr( pointer p )
被标记为 explicit
,这可以防止 unique_ptr
的实例在数组列表初始化时被隐式构造。
2。 std::make_unique
自 C++14 起可用。
在 C++11 中,对这两点的一个可能解决方案是显式构造一个实例,例如std::unique_ptr<Bar>(new Bar( 42, 43 ))
.
您不能从简单指针的数组初始值设定项构造 unique_ptr's
数组的原因是因为 unique_ptr
指针构造函数是 explicit.
要解决此问题,您可以调用 unique_ptr
的显式构造函数,但这很无聊并且容易出现问题,导致首先添加 make_unique
。相反,您可以简单地拥有自己的 compat::make_unique
模板函数,它实际上是 1 行:
template<class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}