Overriding an object in memory with placement newWhat uses are there for “placement new”?Method of derived class needs to downcast its parameterC++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Overloading >> operator for a base classChoice for class designWhy should I use a pointer rather than the object itself?Copying Objects and its data members to another objectoverriding 'virtual void ' c++ errorWhy must we declare virtual methods as suchWhat are the new features in C++17?

Is right click on tables bad UX

Can I pay off my mortgage with a new one?

Anonymous reviewer disclosed his identity. Should I thank him by name?

Coffee Grounds and Gritty Butter Cream Icing

What makes a character irredeemable?

How fast are we moving relative to the CMB?

How much Money Should I save in Order to Generate $1000/Month for the rest of my life?

How to explain that the sums of numerators over sums of denominators isn't the same as the mean of ratios?

Is insurance company’s preferred auto shop biased?

Can I voluntarily exit from the US after a 20 year overstay, or could I be detained at the airport?

Found a minor bug, affecting 1% of users. What should QA do?

Quote to show students don't have to fear making mistakes

How come the Russian cognate for the Czech word "čerstvý" (fresh) means entirely the opposite thing (stale)?

How do I know how many sub-shells deep I am?

How does Donald Trump manage to remain so popular over a rather long period of time?

An example of a "regular poset" which does not belong to a convex polytope

Use floats or doubles when writing mobile games

Can you take the additional action from the fighter's Action Surge feature before you take your regular action?

Determine the Winner of a Game of Australian Football

Would Great Old Ones care about the Blood War?

Reducing laundry

Are there manual immigration checks for non EU citizens in airports when travelling inside the EU?

Scorched receptacle

What benefits are there to blocking most search engines?



Overriding an object in memory with placement new


What uses are there for “placement new”?Method of derived class needs to downcast its parameterC++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Overloading >> operator for a base classChoice for class designWhy should I use a pointer rather than the object itself?Copying Objects and its data members to another objectoverriding 'virtual void ' c++ errorWhy must we declare virtual methods as suchWhat are the new features in C++17?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









15















I have an object which I want to 'transform' into another object. For this I am using a placement new on the first object which creates a new object of the other type on top of its own address.



Consider the following code:



#include <string>
#include <iostream>

class Animal
public:
virtual void voice() = 0;
virtual void transform(void *animal) = 0;
virtual ~Animal() = default;;
;

class Cat : public Animal
public:
std::string name = "CAT";
void voice() override
std::cout << "MEOW I am a " << name << std::endl;

void transform(void *animal) override

;

class Dog : public Animal
public:
std::string name = "DOG";
void voice() override
std::cout << "WOOF I am a " << name << std::endl;

void transform(void *animal) override
new(animal) Cat();

;


You can see that when a Dog is called with transform it creates a new Cat on top of the given address.

Next, I will call the Dog::transform with its own address:



#include <iostream>
#include "Animals.h"

int main()
Cat cat;
Dog dog;
std::cout << "Cat says: ";
cat.voice() ;
std::cout << "Dog says: ";
dog.voice();
dog.transform(&dog);
std::cout << "Dog says: ";
dog.voice();
std::cout << "Dog address says: ";
(&dog)->voice();
return 0;



The results of this is:



Cat says: MEOW I am a CAT
Dog says: WOOF I am a DOG
Dog says: WOOF I am a CAT
Dog address says: MEOW I am a CAT


My questions are:



  1. Is this operation considered safe, or does it leave the object in unstable state?

  2. After the transform I call dog.voice(). It correctly prints the name CAT (it is now a cat), but still writes WOOF I am a, even though I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.









share|improve this question





















  • 8





    I can't cite where in the standard it says that this isn't allowed, but I can say that I get "WOOF I am a CAT" in both of the bottom lines on my system, which is a pretty good indicator that this behavior is not portable.

    – Silvio Mayolo
    Apr 16 at 15:07






  • 2





    If you need this behavior which I would describe as "The object will appear to change it's class", consider using the Gang of Four State Pattern: en.wikipedia.org/wiki/State_pattern

    – Reginald Blue
    Apr 16 at 17:24

















15















I have an object which I want to 'transform' into another object. For this I am using a placement new on the first object which creates a new object of the other type on top of its own address.



Consider the following code:



#include <string>
#include <iostream>

class Animal
public:
virtual void voice() = 0;
virtual void transform(void *animal) = 0;
virtual ~Animal() = default;;
;

class Cat : public Animal
public:
std::string name = "CAT";
void voice() override
std::cout << "MEOW I am a " << name << std::endl;

void transform(void *animal) override

;

class Dog : public Animal
public:
std::string name = "DOG";
void voice() override
std::cout << "WOOF I am a " << name << std::endl;

void transform(void *animal) override
new(animal) Cat();

;


You can see that when a Dog is called with transform it creates a new Cat on top of the given address.

Next, I will call the Dog::transform with its own address:



#include <iostream>
#include "Animals.h"

int main()
Cat cat;
Dog dog;
std::cout << "Cat says: ";
cat.voice() ;
std::cout << "Dog says: ";
dog.voice();
dog.transform(&dog);
std::cout << "Dog says: ";
dog.voice();
std::cout << "Dog address says: ";
(&dog)->voice();
return 0;



The results of this is:



Cat says: MEOW I am a CAT
Dog says: WOOF I am a DOG
Dog says: WOOF I am a CAT
Dog address says: MEOW I am a CAT


My questions are:



  1. Is this operation considered safe, or does it leave the object in unstable state?

  2. After the transform I call dog.voice(). It correctly prints the name CAT (it is now a cat), but still writes WOOF I am a, even though I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.









share|improve this question





















  • 8





    I can't cite where in the standard it says that this isn't allowed, but I can say that I get "WOOF I am a CAT" in both of the bottom lines on my system, which is a pretty good indicator that this behavior is not portable.

    – Silvio Mayolo
    Apr 16 at 15:07






  • 2





    If you need this behavior which I would describe as "The object will appear to change it's class", consider using the Gang of Four State Pattern: en.wikipedia.org/wiki/State_pattern

    – Reginald Blue
    Apr 16 at 17:24













15












15








15


1






I have an object which I want to 'transform' into another object. For this I am using a placement new on the first object which creates a new object of the other type on top of its own address.



Consider the following code:



#include <string>
#include <iostream>

class Animal
public:
virtual void voice() = 0;
virtual void transform(void *animal) = 0;
virtual ~Animal() = default;;
;

class Cat : public Animal
public:
std::string name = "CAT";
void voice() override
std::cout << "MEOW I am a " << name << std::endl;

void transform(void *animal) override

;

class Dog : public Animal
public:
std::string name = "DOG";
void voice() override
std::cout << "WOOF I am a " << name << std::endl;

void transform(void *animal) override
new(animal) Cat();

;


You can see that when a Dog is called with transform it creates a new Cat on top of the given address.

Next, I will call the Dog::transform with its own address:



#include <iostream>
#include "Animals.h"

int main()
Cat cat;
Dog dog;
std::cout << "Cat says: ";
cat.voice() ;
std::cout << "Dog says: ";
dog.voice();
dog.transform(&dog);
std::cout << "Dog says: ";
dog.voice();
std::cout << "Dog address says: ";
(&dog)->voice();
return 0;



The results of this is:



Cat says: MEOW I am a CAT
Dog says: WOOF I am a DOG
Dog says: WOOF I am a CAT
Dog address says: MEOW I am a CAT


My questions are:



  1. Is this operation considered safe, or does it leave the object in unstable state?

  2. After the transform I call dog.voice(). It correctly prints the name CAT (it is now a cat), but still writes WOOF I am a, even though I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.









share|improve this question
















I have an object which I want to 'transform' into another object. For this I am using a placement new on the first object which creates a new object of the other type on top of its own address.



Consider the following code:



#include <string>
#include <iostream>

class Animal
public:
virtual void voice() = 0;
virtual void transform(void *animal) = 0;
virtual ~Animal() = default;;
;

class Cat : public Animal
public:
std::string name = "CAT";
void voice() override
std::cout << "MEOW I am a " << name << std::endl;

void transform(void *animal) override

;

class Dog : public Animal
public:
std::string name = "DOG";
void voice() override
std::cout << "WOOF I am a " << name << std::endl;

void transform(void *animal) override
new(animal) Cat();

;


You can see that when a Dog is called with transform it creates a new Cat on top of the given address.

Next, I will call the Dog::transform with its own address:



#include <iostream>
#include "Animals.h"

int main()
Cat cat;
Dog dog;
std::cout << "Cat says: ";
cat.voice() ;
std::cout << "Dog says: ";
dog.voice();
dog.transform(&dog);
std::cout << "Dog says: ";
dog.voice();
std::cout << "Dog address says: ";
(&dog)->voice();
return 0;



The results of this is:



Cat says: MEOW I am a CAT
Dog says: WOOF I am a DOG
Dog says: WOOF I am a CAT
Dog address says: MEOW I am a CAT


My questions are:



  1. Is this operation considered safe, or does it leave the object in unstable state?

  2. After the transform I call dog.voice(). It correctly prints the name CAT (it is now a cat), but still writes WOOF I am a, even though I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.






c++ placement-new






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Apr 16 at 19:56









John Kugelman

262k59 gold badges428 silver badges477 bronze badges




262k59 gold badges428 silver badges477 bronze badges










asked Apr 16 at 15:00









Guy YafeGuy Yafe

4781 gold badge5 silver badges17 bronze badges




4781 gold badge5 silver badges17 bronze badges










  • 8





    I can't cite where in the standard it says that this isn't allowed, but I can say that I get "WOOF I am a CAT" in both of the bottom lines on my system, which is a pretty good indicator that this behavior is not portable.

    – Silvio Mayolo
    Apr 16 at 15:07






  • 2





    If you need this behavior which I would describe as "The object will appear to change it's class", consider using the Gang of Four State Pattern: en.wikipedia.org/wiki/State_pattern

    – Reginald Blue
    Apr 16 at 17:24












  • 8





    I can't cite where in the standard it says that this isn't allowed, but I can say that I get "WOOF I am a CAT" in both of the bottom lines on my system, which is a pretty good indicator that this behavior is not portable.

    – Silvio Mayolo
    Apr 16 at 15:07






  • 2





    If you need this behavior which I would describe as "The object will appear to change it's class", consider using the Gang of Four State Pattern: en.wikipedia.org/wiki/State_pattern

    – Reginald Blue
    Apr 16 at 17:24







8




8





I can't cite where in the standard it says that this isn't allowed, but I can say that I get "WOOF I am a CAT" in both of the bottom lines on my system, which is a pretty good indicator that this behavior is not portable.

– Silvio Mayolo
Apr 16 at 15:07





I can't cite where in the standard it says that this isn't allowed, but I can say that I get "WOOF I am a CAT" in both of the bottom lines on my system, which is a pretty good indicator that this behavior is not portable.

– Silvio Mayolo
Apr 16 at 15:07




2




2





If you need this behavior which I would describe as "The object will appear to change it's class", consider using the Gang of Four State Pattern: en.wikipedia.org/wiki/State_pattern

– Reginald Blue
Apr 16 at 17:24





If you need this behavior which I would describe as "The object will appear to change it's class", consider using the Gang of Four State Pattern: en.wikipedia.org/wiki/State_pattern

– Reginald Blue
Apr 16 at 17:24












3 Answers
3






active

oldest

votes


















15

















Does this operation considered safe, or does it leave the object in unstable state?




This operation is not safe and causes undefined behavior. Cat and Dog have non trivial destructors so before you can reuse the storage cat and dog have you have to call their destructor so the previous object is cleaned up correctly.




After the transform I call dog.voice(). I prints correctly the CAT name (it is now a cat), but still writes WOOF I am a, even tough I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.




Using dog.voice(); after dog.transform(&dog); is undefined behavior. Since you've reused its storage without destroying it, you have undefined behavior. Lets say you do destroy dog in transform to get rid of that bit of undefined behavior you still aren't out of the woods. Using dog after it has been destroyed is undefined behavior. What you would have to do is capture the pointer placement new returns and use that pointer from then on. You could also use std::launder on dog with a reinterpret_cast to the type you transformed it to but it's not worth since you lose all encapsulation.




You also need to make sure when using placement new that the object you are using is large enough for the object you are constructing. In this case it should be since the classes are the same but a static_assert comparing the sizes will guarantee that and stop the compilation if it is not true.




One way you can fix this is to create a different animal class that acts as a holder of your animal class (I renamed it to Animal_Base in the sample code below). This lets you encapsulate the changing of what type of object an Animal represents. Changing your code to



class Animal_Base 
public:
virtual void voice() = 0;
virtual ~Animal_Base() = default;
;

class Cat : public Animal_Base
public:
std::string name = "CAT";
void voice() override
std::cout << "MEOW I am a " << name << std::endl;

;

class Dog : public Animal_Base
public:
std::string name = "DOG";
void voice() override
std::cout << "WOOF I am a " << name << std::endl;

;

class Animal

std::unique_ptr<Animal_Base> animal;
public:
void voice() animal->voice();
// ask for a T, make sure it is a derived class of Animal_Base, reset pointer to T's type
template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
void transform() animal = std::make_unique<T>();
// Use this to say what type of animal you want it to represent. Doing this instead of making
// Animal a temaplte so you can store Animals in an array
template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
Animal(T&& a) : animal(std::make_unique<T>(std::forward<T>(a)))
;


and then adjusting main to



int main() 

Animal catCat;
Animal dogDog;
std::cout << "Cat says: ";
cat.voice() ;
std::cout << "Dog says: ";
dog.voice();
dog.transform<Cat>();
std::cout << "Dog says: ";
dog.voice();
std::cout << "Dog address says: ";
(&dog)->voice();
return 0;



produces the output



Cat says: MEOW I am a CAT
Dog says: WOOF I am a DOG
Dog says: MEOW I am a CAT
Dog address says: MEOW I am a CAT


and this is safe and portable.






share|improve this answer






















  • 1





    Very well said, and +1 for pointing out more esoteric options like std::launder. The only thing I would add is a recommendation to use standard polymorphism instead of... whatever you call transform().

    – Kevin
    Apr 17 at 4:27












  • @Kevin I was thinking about it an decided to do one better an have added an example of how the OP can get the behavior they are looking for.

    – NathanOliver
    Apr 17 at 12:40


















6
















You have at least three issues with this code:



  • There is no guarantee that when placement new is called the size of the object you are constructing your new object in is sufficient to hold the new object

  • You are not calling destructor of the object used as a placeholder

  • You use the Dog object after it's storage has been reused.





share|improve this answer
































    6
















    1) No, this is not safe for the following reasons:



    • The behavior is undefined and can be different for some compilers.

    • The allocated memory needs to be big enough to hold the newly created structure.

    • Some compilers might call the destructor of the original object even if it is virtual, which would lead to leaks and crashes.

    • In your code, the destructor of the original object is not called, so it can lead to memory leaks.

    2) I observed on MSVC2015 that dog.voice() will call Dog::voice without checking the actual virtual table. In the second case, it checks the virtual table, which has been modified to be Cat::voice. However, as experienced by other users, some other compiler might perform some optimizations and directly call the method that matches the declaration in all cases.






    share|improve this answer






















    • 1





      When you say behavior is not portable you need to explain why. The destructor is already virtual.

      – SergeyA
      Apr 16 at 15:17







    • 1





      I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.

      – Gilles-Philippe Paillé
      Apr 16 at 15:18






    • 1





      Do note there is a virtual destructor in the code in question

      – NathanOliver
      Apr 16 at 15:19







    • 1





      @NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.

      – Gilles-Philippe Paillé
      Apr 16 at 15:21












    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%2f55711220%2foverriding-an-object-in-memory-with-placement-new%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









    15

















    Does this operation considered safe, or does it leave the object in unstable state?




    This operation is not safe and causes undefined behavior. Cat and Dog have non trivial destructors so before you can reuse the storage cat and dog have you have to call their destructor so the previous object is cleaned up correctly.




    After the transform I call dog.voice(). I prints correctly the CAT name (it is now a cat), but still writes WOOF I am a, even tough I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.




    Using dog.voice(); after dog.transform(&dog); is undefined behavior. Since you've reused its storage without destroying it, you have undefined behavior. Lets say you do destroy dog in transform to get rid of that bit of undefined behavior you still aren't out of the woods. Using dog after it has been destroyed is undefined behavior. What you would have to do is capture the pointer placement new returns and use that pointer from then on. You could also use std::launder on dog with a reinterpret_cast to the type you transformed it to but it's not worth since you lose all encapsulation.




    You also need to make sure when using placement new that the object you are using is large enough for the object you are constructing. In this case it should be since the classes are the same but a static_assert comparing the sizes will guarantee that and stop the compilation if it is not true.




    One way you can fix this is to create a different animal class that acts as a holder of your animal class (I renamed it to Animal_Base in the sample code below). This lets you encapsulate the changing of what type of object an Animal represents. Changing your code to



    class Animal_Base 
    public:
    virtual void voice() = 0;
    virtual ~Animal_Base() = default;
    ;

    class Cat : public Animal_Base
    public:
    std::string name = "CAT";
    void voice() override
    std::cout << "MEOW I am a " << name << std::endl;

    ;

    class Dog : public Animal_Base
    public:
    std::string name = "DOG";
    void voice() override
    std::cout << "WOOF I am a " << name << std::endl;

    ;

    class Animal

    std::unique_ptr<Animal_Base> animal;
    public:
    void voice() animal->voice();
    // ask for a T, make sure it is a derived class of Animal_Base, reset pointer to T's type
    template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
    void transform() animal = std::make_unique<T>();
    // Use this to say what type of animal you want it to represent. Doing this instead of making
    // Animal a temaplte so you can store Animals in an array
    template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
    Animal(T&& a) : animal(std::make_unique<T>(std::forward<T>(a)))
    ;


    and then adjusting main to



    int main() 

    Animal catCat;
    Animal dogDog;
    std::cout << "Cat says: ";
    cat.voice() ;
    std::cout << "Dog says: ";
    dog.voice();
    dog.transform<Cat>();
    std::cout << "Dog says: ";
    dog.voice();
    std::cout << "Dog address says: ";
    (&dog)->voice();
    return 0;



    produces the output



    Cat says: MEOW I am a CAT
    Dog says: WOOF I am a DOG
    Dog says: MEOW I am a CAT
    Dog address says: MEOW I am a CAT


    and this is safe and portable.






    share|improve this answer






















    • 1





      Very well said, and +1 for pointing out more esoteric options like std::launder. The only thing I would add is a recommendation to use standard polymorphism instead of... whatever you call transform().

      – Kevin
      Apr 17 at 4:27












    • @Kevin I was thinking about it an decided to do one better an have added an example of how the OP can get the behavior they are looking for.

      – NathanOliver
      Apr 17 at 12:40















    15

















    Does this operation considered safe, or does it leave the object in unstable state?




    This operation is not safe and causes undefined behavior. Cat and Dog have non trivial destructors so before you can reuse the storage cat and dog have you have to call their destructor so the previous object is cleaned up correctly.




    After the transform I call dog.voice(). I prints correctly the CAT name (it is now a cat), but still writes WOOF I am a, even tough I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.




    Using dog.voice(); after dog.transform(&dog); is undefined behavior. Since you've reused its storage without destroying it, you have undefined behavior. Lets say you do destroy dog in transform to get rid of that bit of undefined behavior you still aren't out of the woods. Using dog after it has been destroyed is undefined behavior. What you would have to do is capture the pointer placement new returns and use that pointer from then on. You could also use std::launder on dog with a reinterpret_cast to the type you transformed it to but it's not worth since you lose all encapsulation.




    You also need to make sure when using placement new that the object you are using is large enough for the object you are constructing. In this case it should be since the classes are the same but a static_assert comparing the sizes will guarantee that and stop the compilation if it is not true.




    One way you can fix this is to create a different animal class that acts as a holder of your animal class (I renamed it to Animal_Base in the sample code below). This lets you encapsulate the changing of what type of object an Animal represents. Changing your code to



    class Animal_Base 
    public:
    virtual void voice() = 0;
    virtual ~Animal_Base() = default;
    ;

    class Cat : public Animal_Base
    public:
    std::string name = "CAT";
    void voice() override
    std::cout << "MEOW I am a " << name << std::endl;

    ;

    class Dog : public Animal_Base
    public:
    std::string name = "DOG";
    void voice() override
    std::cout << "WOOF I am a " << name << std::endl;

    ;

    class Animal

    std::unique_ptr<Animal_Base> animal;
    public:
    void voice() animal->voice();
    // ask for a T, make sure it is a derived class of Animal_Base, reset pointer to T's type
    template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
    void transform() animal = std::make_unique<T>();
    // Use this to say what type of animal you want it to represent. Doing this instead of making
    // Animal a temaplte so you can store Animals in an array
    template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
    Animal(T&& a) : animal(std::make_unique<T>(std::forward<T>(a)))
    ;


    and then adjusting main to



    int main() 

    Animal catCat;
    Animal dogDog;
    std::cout << "Cat says: ";
    cat.voice() ;
    std::cout << "Dog says: ";
    dog.voice();
    dog.transform<Cat>();
    std::cout << "Dog says: ";
    dog.voice();
    std::cout << "Dog address says: ";
    (&dog)->voice();
    return 0;



    produces the output



    Cat says: MEOW I am a CAT
    Dog says: WOOF I am a DOG
    Dog says: MEOW I am a CAT
    Dog address says: MEOW I am a CAT


    and this is safe and portable.






    share|improve this answer






















    • 1





      Very well said, and +1 for pointing out more esoteric options like std::launder. The only thing I would add is a recommendation to use standard polymorphism instead of... whatever you call transform().

      – Kevin
      Apr 17 at 4:27












    • @Kevin I was thinking about it an decided to do one better an have added an example of how the OP can get the behavior they are looking for.

      – NathanOliver
      Apr 17 at 12:40













    15














    15










    15










    Does this operation considered safe, or does it leave the object in unstable state?




    This operation is not safe and causes undefined behavior. Cat and Dog have non trivial destructors so before you can reuse the storage cat and dog have you have to call their destructor so the previous object is cleaned up correctly.




    After the transform I call dog.voice(). I prints correctly the CAT name (it is now a cat), but still writes WOOF I am a, even tough I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.




    Using dog.voice(); after dog.transform(&dog); is undefined behavior. Since you've reused its storage without destroying it, you have undefined behavior. Lets say you do destroy dog in transform to get rid of that bit of undefined behavior you still aren't out of the woods. Using dog after it has been destroyed is undefined behavior. What you would have to do is capture the pointer placement new returns and use that pointer from then on. You could also use std::launder on dog with a reinterpret_cast to the type you transformed it to but it's not worth since you lose all encapsulation.




    You also need to make sure when using placement new that the object you are using is large enough for the object you are constructing. In this case it should be since the classes are the same but a static_assert comparing the sizes will guarantee that and stop the compilation if it is not true.




    One way you can fix this is to create a different animal class that acts as a holder of your animal class (I renamed it to Animal_Base in the sample code below). This lets you encapsulate the changing of what type of object an Animal represents. Changing your code to



    class Animal_Base 
    public:
    virtual void voice() = 0;
    virtual ~Animal_Base() = default;
    ;

    class Cat : public Animal_Base
    public:
    std::string name = "CAT";
    void voice() override
    std::cout << "MEOW I am a " << name << std::endl;

    ;

    class Dog : public Animal_Base
    public:
    std::string name = "DOG";
    void voice() override
    std::cout << "WOOF I am a " << name << std::endl;

    ;

    class Animal

    std::unique_ptr<Animal_Base> animal;
    public:
    void voice() animal->voice();
    // ask for a T, make sure it is a derived class of Animal_Base, reset pointer to T's type
    template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
    void transform() animal = std::make_unique<T>();
    // Use this to say what type of animal you want it to represent. Doing this instead of making
    // Animal a temaplte so you can store Animals in an array
    template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
    Animal(T&& a) : animal(std::make_unique<T>(std::forward<T>(a)))
    ;


    and then adjusting main to



    int main() 

    Animal catCat;
    Animal dogDog;
    std::cout << "Cat says: ";
    cat.voice() ;
    std::cout << "Dog says: ";
    dog.voice();
    dog.transform<Cat>();
    std::cout << "Dog says: ";
    dog.voice();
    std::cout << "Dog address says: ";
    (&dog)->voice();
    return 0;



    produces the output



    Cat says: MEOW I am a CAT
    Dog says: WOOF I am a DOG
    Dog says: MEOW I am a CAT
    Dog address says: MEOW I am a CAT


    and this is safe and portable.






    share|improve this answer
















    Does this operation considered safe, or does it leave the object in unstable state?




    This operation is not safe and causes undefined behavior. Cat and Dog have non trivial destructors so before you can reuse the storage cat and dog have you have to call their destructor so the previous object is cleaned up correctly.




    After the transform I call dog.voice(). I prints correctly the CAT name (it is now a cat), but still writes WOOF I am a, even tough I would have thought that it should call the Cat's voice method? (You can see is that I call the same method but by the address ((&dog)->voice()), everything is working properly.




    Using dog.voice(); after dog.transform(&dog); is undefined behavior. Since you've reused its storage without destroying it, you have undefined behavior. Lets say you do destroy dog in transform to get rid of that bit of undefined behavior you still aren't out of the woods. Using dog after it has been destroyed is undefined behavior. What you would have to do is capture the pointer placement new returns and use that pointer from then on. You could also use std::launder on dog with a reinterpret_cast to the type you transformed it to but it's not worth since you lose all encapsulation.




    You also need to make sure when using placement new that the object you are using is large enough for the object you are constructing. In this case it should be since the classes are the same but a static_assert comparing the sizes will guarantee that and stop the compilation if it is not true.




    One way you can fix this is to create a different animal class that acts as a holder of your animal class (I renamed it to Animal_Base in the sample code below). This lets you encapsulate the changing of what type of object an Animal represents. Changing your code to



    class Animal_Base 
    public:
    virtual void voice() = 0;
    virtual ~Animal_Base() = default;
    ;

    class Cat : public Animal_Base
    public:
    std::string name = "CAT";
    void voice() override
    std::cout << "MEOW I am a " << name << std::endl;

    ;

    class Dog : public Animal_Base
    public:
    std::string name = "DOG";
    void voice() override
    std::cout << "WOOF I am a " << name << std::endl;

    ;

    class Animal

    std::unique_ptr<Animal_Base> animal;
    public:
    void voice() animal->voice();
    // ask for a T, make sure it is a derived class of Animal_Base, reset pointer to T's type
    template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
    void transform() animal = std::make_unique<T>();
    // Use this to say what type of animal you want it to represent. Doing this instead of making
    // Animal a temaplte so you can store Animals in an array
    template<typename T, std::enable_if_t<std::is_base_of_v<Animal_Base, T>, bool> = true>
    Animal(T&& a) : animal(std::make_unique<T>(std::forward<T>(a)))
    ;


    and then adjusting main to



    int main() 

    Animal catCat;
    Animal dogDog;
    std::cout << "Cat says: ";
    cat.voice() ;
    std::cout << "Dog says: ";
    dog.voice();
    dog.transform<Cat>();
    std::cout << "Dog says: ";
    dog.voice();
    std::cout << "Dog address says: ";
    (&dog)->voice();
    return 0;



    produces the output



    Cat says: MEOW I am a CAT
    Dog says: WOOF I am a DOG
    Dog says: MEOW I am a CAT
    Dog address says: MEOW I am a CAT


    and this is safe and portable.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Apr 17 at 12:40

























    answered Apr 16 at 15:14









    NathanOliverNathanOliver

    116k19 gold badges185 silver badges264 bronze badges




    116k19 gold badges185 silver badges264 bronze badges










    • 1





      Very well said, and +1 for pointing out more esoteric options like std::launder. The only thing I would add is a recommendation to use standard polymorphism instead of... whatever you call transform().

      – Kevin
      Apr 17 at 4:27












    • @Kevin I was thinking about it an decided to do one better an have added an example of how the OP can get the behavior they are looking for.

      – NathanOliver
      Apr 17 at 12:40












    • 1





      Very well said, and +1 for pointing out more esoteric options like std::launder. The only thing I would add is a recommendation to use standard polymorphism instead of... whatever you call transform().

      – Kevin
      Apr 17 at 4:27












    • @Kevin I was thinking about it an decided to do one better an have added an example of how the OP can get the behavior they are looking for.

      – NathanOliver
      Apr 17 at 12:40







    1




    1





    Very well said, and +1 for pointing out more esoteric options like std::launder. The only thing I would add is a recommendation to use standard polymorphism instead of... whatever you call transform().

    – Kevin
    Apr 17 at 4:27






    Very well said, and +1 for pointing out more esoteric options like std::launder. The only thing I would add is a recommendation to use standard polymorphism instead of... whatever you call transform().

    – Kevin
    Apr 17 at 4:27














    @Kevin I was thinking about it an decided to do one better an have added an example of how the OP can get the behavior they are looking for.

    – NathanOliver
    Apr 17 at 12:40





    @Kevin I was thinking about it an decided to do one better an have added an example of how the OP can get the behavior they are looking for.

    – NathanOliver
    Apr 17 at 12:40













    6
















    You have at least three issues with this code:



    • There is no guarantee that when placement new is called the size of the object you are constructing your new object in is sufficient to hold the new object

    • You are not calling destructor of the object used as a placeholder

    • You use the Dog object after it's storage has been reused.





    share|improve this answer





























      6
















      You have at least three issues with this code:



      • There is no guarantee that when placement new is called the size of the object you are constructing your new object in is sufficient to hold the new object

      • You are not calling destructor of the object used as a placeholder

      • You use the Dog object after it's storage has been reused.





      share|improve this answer



























        6














        6










        6









        You have at least three issues with this code:



        • There is no guarantee that when placement new is called the size of the object you are constructing your new object in is sufficient to hold the new object

        • You are not calling destructor of the object used as a placeholder

        • You use the Dog object after it's storage has been reused.





        share|improve this answer













        You have at least three issues with this code:



        • There is no guarantee that when placement new is called the size of the object you are constructing your new object in is sufficient to hold the new object

        • You are not calling destructor of the object used as a placeholder

        • You use the Dog object after it's storage has been reused.






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Apr 16 at 15:15









        SergeyASergeyA

        49.8k5 gold badges49 silver badges102 bronze badges




        49.8k5 gold badges49 silver badges102 bronze badges
























            6
















            1) No, this is not safe for the following reasons:



            • The behavior is undefined and can be different for some compilers.

            • The allocated memory needs to be big enough to hold the newly created structure.

            • Some compilers might call the destructor of the original object even if it is virtual, which would lead to leaks and crashes.

            • In your code, the destructor of the original object is not called, so it can lead to memory leaks.

            2) I observed on MSVC2015 that dog.voice() will call Dog::voice without checking the actual virtual table. In the second case, it checks the virtual table, which has been modified to be Cat::voice. However, as experienced by other users, some other compiler might perform some optimizations and directly call the method that matches the declaration in all cases.






            share|improve this answer






















            • 1





              When you say behavior is not portable you need to explain why. The destructor is already virtual.

              – SergeyA
              Apr 16 at 15:17







            • 1





              I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.

              – Gilles-Philippe Paillé
              Apr 16 at 15:18






            • 1





              Do note there is a virtual destructor in the code in question

              – NathanOliver
              Apr 16 at 15:19







            • 1





              @NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.

              – Gilles-Philippe Paillé
              Apr 16 at 15:21















            6
















            1) No, this is not safe for the following reasons:



            • The behavior is undefined and can be different for some compilers.

            • The allocated memory needs to be big enough to hold the newly created structure.

            • Some compilers might call the destructor of the original object even if it is virtual, which would lead to leaks and crashes.

            • In your code, the destructor of the original object is not called, so it can lead to memory leaks.

            2) I observed on MSVC2015 that dog.voice() will call Dog::voice without checking the actual virtual table. In the second case, it checks the virtual table, which has been modified to be Cat::voice. However, as experienced by other users, some other compiler might perform some optimizations and directly call the method that matches the declaration in all cases.






            share|improve this answer






















            • 1





              When you say behavior is not portable you need to explain why. The destructor is already virtual.

              – SergeyA
              Apr 16 at 15:17







            • 1





              I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.

              – Gilles-Philippe Paillé
              Apr 16 at 15:18






            • 1





              Do note there is a virtual destructor in the code in question

              – NathanOliver
              Apr 16 at 15:19







            • 1





              @NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.

              – Gilles-Philippe Paillé
              Apr 16 at 15:21













            6














            6










            6









            1) No, this is not safe for the following reasons:



            • The behavior is undefined and can be different for some compilers.

            • The allocated memory needs to be big enough to hold the newly created structure.

            • Some compilers might call the destructor of the original object even if it is virtual, which would lead to leaks and crashes.

            • In your code, the destructor of the original object is not called, so it can lead to memory leaks.

            2) I observed on MSVC2015 that dog.voice() will call Dog::voice without checking the actual virtual table. In the second case, it checks the virtual table, which has been modified to be Cat::voice. However, as experienced by other users, some other compiler might perform some optimizations and directly call the method that matches the declaration in all cases.






            share|improve this answer















            1) No, this is not safe for the following reasons:



            • The behavior is undefined and can be different for some compilers.

            • The allocated memory needs to be big enough to hold the newly created structure.

            • Some compilers might call the destructor of the original object even if it is virtual, which would lead to leaks and crashes.

            • In your code, the destructor of the original object is not called, so it can lead to memory leaks.

            2) I observed on MSVC2015 that dog.voice() will call Dog::voice without checking the actual virtual table. In the second case, it checks the virtual table, which has been modified to be Cat::voice. However, as experienced by other users, some other compiler might perform some optimizations and directly call the method that matches the declaration in all cases.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Apr 16 at 19:05

























            answered Apr 16 at 15:13









            Gilles-Philippe PailléGilles-Philippe Paillé

            1,8691 gold badge2 silver badges14 bronze badges




            1,8691 gold badge2 silver badges14 bronze badges










            • 1





              When you say behavior is not portable you need to explain why. The destructor is already virtual.

              – SergeyA
              Apr 16 at 15:17







            • 1





              I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.

              – Gilles-Philippe Paillé
              Apr 16 at 15:18






            • 1





              Do note there is a virtual destructor in the code in question

              – NathanOliver
              Apr 16 at 15:19







            • 1





              @NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.

              – Gilles-Philippe Paillé
              Apr 16 at 15:21












            • 1





              When you say behavior is not portable you need to explain why. The destructor is already virtual.

              – SergeyA
              Apr 16 at 15:17







            • 1





              I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.

              – Gilles-Philippe Paillé
              Apr 16 at 15:18






            • 1





              Do note there is a virtual destructor in the code in question

              – NathanOliver
              Apr 16 at 15:19







            • 1





              @NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.

              – Gilles-Philippe Paillé
              Apr 16 at 15:21







            1




            1





            When you say behavior is not portable you need to explain why. The destructor is already virtual.

            – SergeyA
            Apr 16 at 15:17






            When you say behavior is not portable you need to explain why. The destructor is already virtual.

            – SergeyA
            Apr 16 at 15:17





            1




            1





            I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.

            – Gilles-Philippe Paillé
            Apr 16 at 15:18





            I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.

            – Gilles-Philippe Paillé
            Apr 16 at 15:18




            1




            1





            Do note there is a virtual destructor in the code in question

            – NathanOliver
            Apr 16 at 15:19






            Do note there is a virtual destructor in the code in question

            – NathanOliver
            Apr 16 at 15:19





            1




            1





            @NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.

            – Gilles-Philippe Paillé
            Apr 16 at 15:21





            @NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.

            – Gilles-Philippe Paillé
            Apr 16 at 15:21


















            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%2f55711220%2foverriding-an-object-in-memory-with-placement-new%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?

            Where does the image of a data connector as a sharp metal spike originate from?Where does the concept of infected people turning into zombies only after death originate from?Where does the motif of a reanimated human head originate?Where did the notion that Dragons could speak originate?Where does the archetypal image of the 'Grey' alien come from?Where did the suffix '-Man' originate?Where does the notion of being injured or killed by an illusion originate?Where did the term “sophont” originate?Where does the trope of magic spells being driven by advanced technology originate from?Where did the term “the living impaired” originate?