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;









21


















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?










share|improve this question




















  • 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

















21


















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?










share|improve this question




















  • 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













21













21









21


1






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?










share|improve this question














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






share|improve this question













share|improve this question











share|improve this question




share|improve this question










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 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












  • 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







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












3 Answers
3






active

oldest

votes


















25



















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 to pointer




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).






share|improve this answer






















  • 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


















13



















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 to pointer



...




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.)






share|improve this answer


































    7



















    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.






    share|improve this answer


























      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
      );



      );














      draft saved

      draft discarded
















      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









      25



















      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 to pointer




      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).






      share|improve this answer






















      • 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















      25



















      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 to pointer




      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).






      share|improve this answer






















      • 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













      25















      25











      25









      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 to pointer




      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).






      share|improve this answer
















      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 to pointer




      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).







      share|improve this answer















      share|improve this answer




      share|improve this answer








      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 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












      • 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







      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













      13



















      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 to pointer



      ...




      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.)






      share|improve this answer































        13



















        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 to pointer



        ...




        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.)






        share|improve this answer





























          13















          13











          13









          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 to pointer



          ...




          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.)






          share|improve this answer
















          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 to pointer



          ...




          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.)







          share|improve this answer















          share|improve this answer




          share|improve this answer








          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
























              7



















              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.






              share|improve this answer





























                7



















                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.






                share|improve this answer



























                  7















                  7











                  7









                  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.






                  share|improve this answer














                  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.







                  share|improve this answer













                  share|improve this answer




                  share|improve this answer










                  answered Oct 1 at 8:50









                  lubgrlubgr

                  29.1k3 gold badges43 silver badges88 bronze badges




                  29.1k3 gold badges43 silver badges88 bronze badges































                      draft saved

                      draft discarded















































                      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.




                      draft saved


                      draft discarded














                      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





















































                      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









                      Popular posts from this blog

                      Tamil (spriik) Luke uk diar | Nawigatjuun

                      Align equal signs while including text over equalitiesAMS align: left aligned text/math plus multicolumn alignmentMultiple alignmentsAligning equations in multiple placesNumbering and aligning an equation with multiple columnsHow to align one equation with another multline equationUsing \ in environments inside the begintabularxNumber equations and preserving alignment of equal signsHow can I align equations to the left and to the right?Double equation alignment problem within align enviromentAligned within align: Why are they right-aligned?

                      Training a classifier when some of the features are unknownWhy does Gradient Boosting regression predict negative values when there are no negative y-values in my training set?How to improve an existing (trained) classifier?What is effect when I set up some self defined predisctor variables?Why Matlab neural network classification returns decimal values on prediction dataset?Fitting and transforming text data in training, testing, and validation setsHow to quantify the performance of the classifier (multi-class SVM) using the test data?How do I control for some patients providing multiple samples in my training data?Training and Test setTraining a convolutional neural network for image denoising in MatlabShouldn't an autoencoder with #(neurons in hidden layer) = #(neurons in input layer) be “perfect”?