std::make_unique<T>
needs C++ 17
feature.It's a pity that I have to use C++11
. When I am porting the code snippet to C++11
, I found a strange thing.
The code snippet which uses make_unique
works well:
#include <iostream>
#include <memory>
struct View;
struct Database : public std::enable_shared_from_this<Database>
{
static std::shared_ptr<Database> Create(){ return std::shared_ptr<Database>(new Database());}
std::unique_ptr<View> GetView() { return std::make_unique<View>(shared_from_this()); } //works well
~Database() {std::cout << "Database is destoryed" << std::endl;}
private:
Database(){};
};
struct View
{
std::shared_ptr<Database> db;
View(std::shared_ptr<Database> db) : db(std::move(db)) {}
~View() {std::cout << "View is destoryed" << std::endl;}
};
int main()
{
std::shared_ptr<View> view;
{
auto db{Database::Create()} ;
view = db->GetView();
}
}
whereas the code snippet below does not compile:
#include <iostream>
#include <memory>
struct View;
struct Database : public std::enable_shared_from_this<Database>
{
static std::shared_ptr<Database> Create(){ return std::shared_ptr<Database>(new Database());}
std::unique_ptr<View> GetView() { return std::unique_ptr<View>(new View(shared_from_this())); } //here is the modification
~Database() {std::cout << "Database is destoryed" << std::endl;}
private:
Database(){};
};
struct View
{
std::shared_ptr<Database> db;
View(std::shared_ptr<Database> db) : db(std::move(db)) {}
~View() {std::cout << "View is destoryed" << std::endl;}
};
int main()
{
std::shared_ptr<View> view;
{
auto db{Database::Create()} ;
view = db->GetView();
}
}
Here is what the complier complains:
<source>: In member function 'std::unique_ptr<View> Database::GetView()':
<source>:10:95: error: invalid use of incomplete type 'struct View'
10 | std::unique_ptr<View> GetView() { return std::unique_ptr<View>(new View(shared_from_this())); } //here is the modification
| ^
<source>:4:8: note: forward declaration of 'struct View'
4 | struct View;
| ^~~~
After I did some modification for the second code snippet,this one works:
#include <iostream>
#include <memory>
struct Database;
struct View
{
std::shared_ptr<Database> db;
View(std::shared_ptr<Database> db) : db(std::move(db)) {}
~View() {std::cout << "View is destoryed" << std::endl;}
};
struct Database : public std::enable_shared_from_this<Database>
{
static std::shared_ptr<Database> Create(){ return std::shared_ptr<Database>(new Database());}
#if 0
std::unique_ptr<View> GetView() { return std::make_unique<View>(shared_from_this()); } //works well
#else
std::unique_ptr<View> GetView() { return std::unique_ptr<View>(new View(shared_from_this())); }
#endif
~Database() {std::cout << "Database is destoryed" << std::endl;}
private:
Database(){};
};
int main()
{
std::shared_ptr<View> view;
{
auto db{Database::Create()} ;
view = db->GetView();
}
}
Why std::make_unique<View>(shared_from_this())
works even if there is only a forward delaration for View
before Database
's definition, whereas the compiler complains about std::unique_ptr<View>(new View(shared_from_this())
under the same condition?
Why
std::make_unique<View>(shared_from_this())
works even if there is only a forward delaration forView
beforeDatabase
's definition, whereas the compiler complains aboutstd::unique_ptr<View>(new View(shared_from_this())
under the same condition?
Consider this simplified example:
#include <memory>
struct foo;
std::unique_ptr<foo> make_foo_1() { return std::make_unique<foo>(); } // OK
std::unique_ptr<foo> make_foo_2() { return std::unique_ptr<foo>(new foo); } // ERROR
struct foo {};
In make_foo_1
, std::unique_ptr<foo>
is made a dependent type in make_unique<foo>
which means that it'll postpone binding to unique_ptr<foo>
.
But "Non-dependent names are looked up and bound at the point of template definition" (i.e., the definition of std::unique_ptr<foo>
) which means that, in make_foo_2
, the definition of foo
must have already been seen by the compiler or else it'll complain about foo
being an incomplete type.