Why does unique_ptr implicitly cast to unique_ptr?Method of derived class needs to downcast its parameterIs List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?Low level details of inheritance and polymorphismC++ Problem: Class Promotion using derived classProvide array of derived objects to function that operates on base objectsWhy does changing 0.1f to 0 slow down performance by 10x?How can I pass variables meant for a trigger function in SQLite?C++ multiple inheritance with base classes deriving from the same classTemplates and inheritance, how to call base virtual method
How to know if password in /etc/shadow is hashed with SHA or MD?
"Sack" data structure in C#
How to get a bowl with one liter of water
Why one result is so wide in this logistic multiple regession
Why aren't we seeing carbon taxes in practice?
Is it possible to kill parasitic worms by intoxicating oneself?
How to optimise the use of 10 nuclear fuel pellets in medieval period?
What is the structure in this question? "it's difficult knowing which one to choose."
Speedup or Caching for a Multi-Iteration MIP problem
Six letter words from "MONSTER"
What's the name of this retro Simpsons videogame?
Has any person or company ever become a sovereign state?
Advent calendar
Check if simple regex matches string
Is the endomorphism ring of a module over a non-commutative ring always non-commutative?
How does the bypass air provide thrust?
Can a polling station shut early if everyone has voted?
What to do with excess co-ax cable
Why are bicycle tires incapable of maintaining pressure over time, while car tyres seem to have less of a problem?
The key signatures C-flat minor and G-flat minor: do they exist?
What license do I use when I don't want stock image companies charging people money for photos?
How to quickly type a C expression where the assigned-to variable is repeated?
Is it principled to tip less if a pricey restaurant doesn't accept Visa or Mastercard?
Why is wired Ethernet losing its speed advantage over wireless?
Why does unique_ptr implicitly cast to unique_ptr?
Method of derived class needs to downcast its parameterIs List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?Low level details of inheritance and polymorphismC++ Problem: Class Promotion using derived classProvide array of derived objects to function that operates on base objectsWhy does changing 0.1f to 0 slow down performance by 10x?How can I pass variables meant for a trigger function in SQLite?C++ multiple inheritance with base classes deriving from the same classTemplates and inheritance, how to call base virtual method
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
I wrote the following code that uses unique_ptr<Derived>
where a unique_ptr<Base>
is expected
class Base
int i;
public:
Base( int i ) : i(i)
int getI() const return i;
;
class Derived : public Base
float f;
public:
Derived( int i, float f ) : Base(i), f(f)
float getF() const return f;
;
void printBase( unique_ptr<Base> base )
cout << "f: " << base->getI() << endl;
unique_ptr<Base> makeBase()
return make_unique<Derived>( 2, 3.0f );
unique_ptr<Derived> makeDerived()
return make_unique<Derived>( 2, 3.0f );
int main( int argc, char * argv [] )
unique_ptr<Base> base1 = makeBase();
unique_ptr<Base> base2 = makeDerived();
printBase( make_unique<Derived>( 2, 3.0f ) );
return 0;
and i expected this code to not compile, because according to my understanding unique_ptr<Base>
and unique_ptr<Derived>
are unrelated types and unique_ptr<Derived>
isn't in fact derived from unique_ptr<Base>
so the assignment shouldn't work.
But thanks to some magic it works, and i don't understand why, or even if it's safe to do so.
Can someone explain please?
c++ templates inheritance unique-ptr
add a comment
|
I wrote the following code that uses unique_ptr<Derived>
where a unique_ptr<Base>
is expected
class Base
int i;
public:
Base( int i ) : i(i)
int getI() const return i;
;
class Derived : public Base
float f;
public:
Derived( int i, float f ) : Base(i), f(f)
float getF() const return f;
;
void printBase( unique_ptr<Base> base )
cout << "f: " << base->getI() << endl;
unique_ptr<Base> makeBase()
return make_unique<Derived>( 2, 3.0f );
unique_ptr<Derived> makeDerived()
return make_unique<Derived>( 2, 3.0f );
int main( int argc, char * argv [] )
unique_ptr<Base> base1 = makeBase();
unique_ptr<Base> base2 = makeDerived();
printBase( make_unique<Derived>( 2, 3.0f ) );
return 0;
and i expected this code to not compile, because according to my understanding unique_ptr<Base>
and unique_ptr<Derived>
are unrelated types and unique_ptr<Derived>
isn't in fact derived from unique_ptr<Base>
so the assignment shouldn't work.
But thanks to some magic it works, and i don't understand why, or even if it's safe to do so.
Can someone explain please?
c++ templates inheritance unique-ptr
3
smart pointers are to enrich what pointers can do not to limit it. If this wasnt possibleunique_ptr
would be rather useless in the presence of inheritance
– formerlyknownas_463035818
Oct 1 at 8:49
3
"But thanks to some magic it works". Nearly, you got UB asBase
doesn't have virtual destructor.
– Jarod42
Oct 1 at 12:43
add a comment
|
I wrote the following code that uses unique_ptr<Derived>
where a unique_ptr<Base>
is expected
class Base
int i;
public:
Base( int i ) : i(i)
int getI() const return i;
;
class Derived : public Base
float f;
public:
Derived( int i, float f ) : Base(i), f(f)
float getF() const return f;
;
void printBase( unique_ptr<Base> base )
cout << "f: " << base->getI() << endl;
unique_ptr<Base> makeBase()
return make_unique<Derived>( 2, 3.0f );
unique_ptr<Derived> makeDerived()
return make_unique<Derived>( 2, 3.0f );
int main( int argc, char * argv [] )
unique_ptr<Base> base1 = makeBase();
unique_ptr<Base> base2 = makeDerived();
printBase( make_unique<Derived>( 2, 3.0f ) );
return 0;
and i expected this code to not compile, because according to my understanding unique_ptr<Base>
and unique_ptr<Derived>
are unrelated types and unique_ptr<Derived>
isn't in fact derived from unique_ptr<Base>
so the assignment shouldn't work.
But thanks to some magic it works, and i don't understand why, or even if it's safe to do so.
Can someone explain please?
c++ templates inheritance unique-ptr
I wrote the following code that uses unique_ptr<Derived>
where a unique_ptr<Base>
is expected
class Base
int i;
public:
Base( int i ) : i(i)
int getI() const return i;
;
class Derived : public Base
float f;
public:
Derived( int i, float f ) : Base(i), f(f)
float getF() const return f;
;
void printBase( unique_ptr<Base> base )
cout << "f: " << base->getI() << endl;
unique_ptr<Base> makeBase()
return make_unique<Derived>( 2, 3.0f );
unique_ptr<Derived> makeDerived()
return make_unique<Derived>( 2, 3.0f );
int main( int argc, char * argv [] )
unique_ptr<Base> base1 = makeBase();
unique_ptr<Base> base2 = makeDerived();
printBase( make_unique<Derived>( 2, 3.0f ) );
return 0;
and i expected this code to not compile, because according to my understanding unique_ptr<Base>
and unique_ptr<Derived>
are unrelated types and unique_ptr<Derived>
isn't in fact derived from unique_ptr<Base>
so the assignment shouldn't work.
But thanks to some magic it works, and i don't understand why, or even if it's safe to do so.
Can someone explain please?
c++ templates inheritance unique-ptr
c++ templates inheritance unique-ptr
asked Oct 1 at 8:44
Youda008Youda008
1,0989 silver badges21 bronze badges
1,0989 silver badges21 bronze badges
3
smart pointers are to enrich what pointers can do not to limit it. If this wasnt possibleunique_ptr
would be rather useless in the presence of inheritance
– formerlyknownas_463035818
Oct 1 at 8:49
3
"But thanks to some magic it works". Nearly, you got UB asBase
doesn't have virtual destructor.
– Jarod42
Oct 1 at 12:43
add a comment
|
3
smart pointers are to enrich what pointers can do not to limit it. If this wasnt possibleunique_ptr
would be rather useless in the presence of inheritance
– formerlyknownas_463035818
Oct 1 at 8:49
3
"But thanks to some magic it works". Nearly, you got UB asBase
doesn't have virtual destructor.
– Jarod42
Oct 1 at 12:43
3
3
smart pointers are to enrich what pointers can do not to limit it. If this wasnt possible
unique_ptr
would be rather useless in the presence of inheritance– formerlyknownas_463035818
Oct 1 at 8:49
smart pointers are to enrich what pointers can do not to limit it. If this wasnt possible
unique_ptr
would be rather useless in the presence of inheritance– formerlyknownas_463035818
Oct 1 at 8:49
3
3
"But thanks to some magic it works". Nearly, you got UB as
Base
doesn't have virtual destructor.– Jarod42
Oct 1 at 12:43
"But thanks to some magic it works". Nearly, you got UB as
Base
doesn't have virtual destructor.– Jarod42
Oct 1 at 12:43
add a comment
|
3 Answers
3
active
oldest
votes
The bit of magic you're looking for is the converting constructor #6 here:
template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;
It enables constructing a std::unique_ptr<T>
implicitly from an expiring std::unique_ptr<U>
if (glossing over deleters for clarity):
unique_ptr<U, E>::pointer
is implicitly convertible topointer
Which is to say, it mimicks implicit raw pointer conversions, including derived-to-base conversions, and does what you expect™ safely (in terms of lifetime – you still need to ensure that the base type can be deleted polymorphically).
2
AFAIK the deleter ofBase
won't call the destructor ofDerived
, so I'm not sure whether it's really safe. (It's no less safe than raw pointer, admittedly.)
– cpplearner
Oct 1 at 10:02
add a comment
|
Because std::unique_ptr
has a converting constructor as
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
and
This constructor only participates in overload resolution if all of
the following is true:
a)
unique_ptr<U, E>::pointer
is implicitly convertible topointer
...
A Derived*
could convert to Base*
implicitly, then the converting constructor could be applied for this case. Then a std::unique_ptr<Base>
could be converted from a std::unique_ptr<Derived>
implicitly just as the raw pointer does. (Note that the std::unique_ptr<Derived>
has to be an rvalue for constructing std::unique_ptr<Base>
because of the characteristic of std::unique_ptr
.)
add a comment
|
You can implicitly construct a std::unique_ptr<T>
instance from an rvalue of std::unique_ptr<S>
whenever S
is convertible to T
. This is due to constructor #6 here. Ownership is transferred in this case.
In your example, you have only rvalues of type std::uinque_ptr<Derived>
(because the return value of std::make_unique
is an rvalue), and when you use that as a std::unique_ptr<Base>
, the constructor mentioned above is invoked. The std::unique_ptr<Derived>
objects in question hence only live for a short amount of time, i.e. they are created, then ownership is passed to the std::unique_ptr<Base>
object that is used further on.
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58181090%2fwhy-does-unique-ptrderived-implicitly-cast-to-unique-ptrbase%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
The bit of magic you're looking for is the converting constructor #6 here:
template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;
It enables constructing a std::unique_ptr<T>
implicitly from an expiring std::unique_ptr<U>
if (glossing over deleters for clarity):
unique_ptr<U, E>::pointer
is implicitly convertible topointer
Which is to say, it mimicks implicit raw pointer conversions, including derived-to-base conversions, and does what you expect™ safely (in terms of lifetime – you still need to ensure that the base type can be deleted polymorphically).
2
AFAIK the deleter ofBase
won't call the destructor ofDerived
, so I'm not sure whether it's really safe. (It's no less safe than raw pointer, admittedly.)
– cpplearner
Oct 1 at 10:02
add a comment
|
The bit of magic you're looking for is the converting constructor #6 here:
template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;
It enables constructing a std::unique_ptr<T>
implicitly from an expiring std::unique_ptr<U>
if (glossing over deleters for clarity):
unique_ptr<U, E>::pointer
is implicitly convertible topointer
Which is to say, it mimicks implicit raw pointer conversions, including derived-to-base conversions, and does what you expect™ safely (in terms of lifetime – you still need to ensure that the base type can be deleted polymorphically).
2
AFAIK the deleter ofBase
won't call the destructor ofDerived
, so I'm not sure whether it's really safe. (It's no less safe than raw pointer, admittedly.)
– cpplearner
Oct 1 at 10:02
add a comment
|
The bit of magic you're looking for is the converting constructor #6 here:
template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;
It enables constructing a std::unique_ptr<T>
implicitly from an expiring std::unique_ptr<U>
if (glossing over deleters for clarity):
unique_ptr<U, E>::pointer
is implicitly convertible topointer
Which is to say, it mimicks implicit raw pointer conversions, including derived-to-base conversions, and does what you expect™ safely (in terms of lifetime – you still need to ensure that the base type can be deleted polymorphically).
The bit of magic you're looking for is the converting constructor #6 here:
template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;
It enables constructing a std::unique_ptr<T>
implicitly from an expiring std::unique_ptr<U>
if (glossing over deleters for clarity):
unique_ptr<U, E>::pointer
is implicitly convertible topointer
Which is to say, it mimicks implicit raw pointer conversions, including derived-to-base conversions, and does what you expect™ safely (in terms of lifetime – you still need to ensure that the base type can be deleted polymorphically).
edited Oct 1 at 10:07
answered Oct 1 at 8:50
QuentinQuentin
53k6 gold badges101 silver badges158 bronze badges
53k6 gold badges101 silver badges158 bronze badges
2
AFAIK the deleter ofBase
won't call the destructor ofDerived
, so I'm not sure whether it's really safe. (It's no less safe than raw pointer, admittedly.)
– cpplearner
Oct 1 at 10:02
add a comment
|
2
AFAIK the deleter ofBase
won't call the destructor ofDerived
, so I'm not sure whether it's really safe. (It's no less safe than raw pointer, admittedly.)
– cpplearner
Oct 1 at 10:02
2
2
AFAIK the deleter of
Base
won't call the destructor of Derived
, so I'm not sure whether it's really safe. (It's no less safe than raw pointer, admittedly.)– cpplearner
Oct 1 at 10:02
AFAIK the deleter of
Base
won't call the destructor of Derived
, so I'm not sure whether it's really safe. (It's no less safe than raw pointer, admittedly.)– cpplearner
Oct 1 at 10:02
add a comment
|
Because std::unique_ptr
has a converting constructor as
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
and
This constructor only participates in overload resolution if all of
the following is true:
a)
unique_ptr<U, E>::pointer
is implicitly convertible topointer
...
A Derived*
could convert to Base*
implicitly, then the converting constructor could be applied for this case. Then a std::unique_ptr<Base>
could be converted from a std::unique_ptr<Derived>
implicitly just as the raw pointer does. (Note that the std::unique_ptr<Derived>
has to be an rvalue for constructing std::unique_ptr<Base>
because of the characteristic of std::unique_ptr
.)
add a comment
|
Because std::unique_ptr
has a converting constructor as
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
and
This constructor only participates in overload resolution if all of
the following is true:
a)
unique_ptr<U, E>::pointer
is implicitly convertible topointer
...
A Derived*
could convert to Base*
implicitly, then the converting constructor could be applied for this case. Then a std::unique_ptr<Base>
could be converted from a std::unique_ptr<Derived>
implicitly just as the raw pointer does. (Note that the std::unique_ptr<Derived>
has to be an rvalue for constructing std::unique_ptr<Base>
because of the characteristic of std::unique_ptr
.)
add a comment
|
Because std::unique_ptr
has a converting constructor as
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
and
This constructor only participates in overload resolution if all of
the following is true:
a)
unique_ptr<U, E>::pointer
is implicitly convertible topointer
...
A Derived*
could convert to Base*
implicitly, then the converting constructor could be applied for this case. Then a std::unique_ptr<Base>
could be converted from a std::unique_ptr<Derived>
implicitly just as the raw pointer does. (Note that the std::unique_ptr<Derived>
has to be an rvalue for constructing std::unique_ptr<Base>
because of the characteristic of std::unique_ptr
.)
Because std::unique_ptr
has a converting constructor as
template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;
and
This constructor only participates in overload resolution if all of
the following is true:
a)
unique_ptr<U, E>::pointer
is implicitly convertible topointer
...
A Derived*
could convert to Base*
implicitly, then the converting constructor could be applied for this case. Then a std::unique_ptr<Base>
could be converted from a std::unique_ptr<Derived>
implicitly just as the raw pointer does. (Note that the std::unique_ptr<Derived>
has to be an rvalue for constructing std::unique_ptr<Base>
because of the characteristic of std::unique_ptr
.)
edited Oct 2 at 2:11
answered Oct 1 at 8:48
songyuanyaosongyuanyao
112k13 gold badges214 silver badges294 bronze badges
112k13 gold badges214 silver badges294 bronze badges
add a comment
|
add a comment
|
You can implicitly construct a std::unique_ptr<T>
instance from an rvalue of std::unique_ptr<S>
whenever S
is convertible to T
. This is due to constructor #6 here. Ownership is transferred in this case.
In your example, you have only rvalues of type std::uinque_ptr<Derived>
(because the return value of std::make_unique
is an rvalue), and when you use that as a std::unique_ptr<Base>
, the constructor mentioned above is invoked. The std::unique_ptr<Derived>
objects in question hence only live for a short amount of time, i.e. they are created, then ownership is passed to the std::unique_ptr<Base>
object that is used further on.
add a comment
|
You can implicitly construct a std::unique_ptr<T>
instance from an rvalue of std::unique_ptr<S>
whenever S
is convertible to T
. This is due to constructor #6 here. Ownership is transferred in this case.
In your example, you have only rvalues of type std::uinque_ptr<Derived>
(because the return value of std::make_unique
is an rvalue), and when you use that as a std::unique_ptr<Base>
, the constructor mentioned above is invoked. The std::unique_ptr<Derived>
objects in question hence only live for a short amount of time, i.e. they are created, then ownership is passed to the std::unique_ptr<Base>
object that is used further on.
add a comment
|
You can implicitly construct a std::unique_ptr<T>
instance from an rvalue of std::unique_ptr<S>
whenever S
is convertible to T
. This is due to constructor #6 here. Ownership is transferred in this case.
In your example, you have only rvalues of type std::uinque_ptr<Derived>
(because the return value of std::make_unique
is an rvalue), and when you use that as a std::unique_ptr<Base>
, the constructor mentioned above is invoked. The std::unique_ptr<Derived>
objects in question hence only live for a short amount of time, i.e. they are created, then ownership is passed to the std::unique_ptr<Base>
object that is used further on.
You can implicitly construct a std::unique_ptr<T>
instance from an rvalue of std::unique_ptr<S>
whenever S
is convertible to T
. This is due to constructor #6 here. Ownership is transferred in this case.
In your example, you have only rvalues of type std::uinque_ptr<Derived>
(because the return value of std::make_unique
is an rvalue), and when you use that as a std::unique_ptr<Base>
, the constructor mentioned above is invoked. The std::unique_ptr<Derived>
objects in question hence only live for a short amount of time, i.e. they are created, then ownership is passed to the std::unique_ptr<Base>
object that is used further on.
answered Oct 1 at 8:50
lubgrlubgr
29.1k3 gold badges43 silver badges88 bronze badges
29.1k3 gold badges43 silver badges88 bronze badges
add a comment
|
add a comment
|
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f58181090%2fwhy-does-unique-ptrderived-implicitly-cast-to-unique-ptrbase%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
smart pointers are to enrich what pointers can do not to limit it. If this wasnt possible
unique_ptr
would be rather useless in the presence of inheritance– formerlyknownas_463035818
Oct 1 at 8:49
3
"But thanks to some magic it works". Nearly, you got UB as
Base
doesn't have virtual destructor.– Jarod42
Oct 1 at 12:43