Overriding an object in memory with placement new Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) Data science time! April 2019 and salary with experience Should we burninate the [wrap] tag? The Ask Question Wizard is Live!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?
English words in a non-english sci-fi novel
What does an IRS interview request entail when called in to verify expenses for a sole proprietor small business?
Apollo command module space walk?
How to react to hostile behavior from a senior developer?
Book where humans were engineered with genes from animal species to survive hostile planets
How does the particle を relate to the verb 行く in the structure「A を + B に行く」?
How to bypass password on Windows XP account?
List of Python versions
Can I cast Passwall to drop an enemy into a 20-foot pit?
Abandoning the Ordinary World
Using et al. for a last / senior author rather than for a first author
Why are there no cargo aircraft with "flying wing" design?
How to align text above triangle figure
What does this icon in iOS Stardew Valley mean?
Sci-Fi book where patients in a coma ward all live in a subconscious world linked together
Why did the rest of the Eastern Bloc not invade Yugoslavia?
What is the logic behind the Maharil's explanation of why we don't say שעשה ניסים on Pesach?
Can a non-EU citizen traveling with me come with me through the EU passport line?
Withdrew £2800, but only £2000 shows as withdrawn on online banking; what are my obligations?
Why aren't air breathing engines used as small first stages
3 doors, three guards, one stone
What's the meaning of 間時肆拾貳 at a car parking sign
Should I use a zero-interest credit card for a large one-time purchase?
How do pianists reach extremely loud dynamics?
Overriding an object in memory with placement new
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
Data science time! April 2019 and salary with experience
Should we burninate the [wrap] tag?
The Ask Question Wizard is Live!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 height:90px;width:728px;box-sizing:border-box;
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:
- Is this operation considered safe, or does it leave the object in unstable state?
- After the transform I call
dog.voice()
. It correctly prints the nameCAT
(it is now a cat), but still writesWOOF I am a
, even though I would have thought that it should call theCat
'svoice
method? (You can see is that I call the same method but by the address ((&dog)->voice()
), everything is working properly.
c++ placement-new
add a comment |
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:
- Is this operation considered safe, or does it leave the object in unstable state?
- After the transform I call
dog.voice()
. It correctly prints the nameCAT
(it is now a cat), but still writesWOOF I am a
, even though I would have thought that it should call theCat
'svoice
method? (You can see is that I call the same method but by the address ((&dog)->voice()
), everything is working properly.
c++ placement-new
7
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
12 hours ago
1
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
10 hours ago
add a comment |
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:
- Is this operation considered safe, or does it leave the object in unstable state?
- After the transform I call
dog.voice()
. It correctly prints the nameCAT
(it is now a cat), but still writesWOOF I am a
, even though I would have thought that it should call theCat
'svoice
method? (You can see is that I call the same method but by the address ((&dog)->voice()
), everything is working properly.
c++ placement-new
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:
- Is this operation considered safe, or does it leave the object in unstable state?
- After the transform I call
dog.voice()
. It correctly prints the nameCAT
(it is now a cat), but still writesWOOF I am a
, even though I would have thought that it should call theCat
'svoice
method? (You can see is that I call the same method but by the address ((&dog)->voice()
), everything is working properly.
c++ placement-new
c++ placement-new
edited 8 hours ago
John Kugelman
249k54407460
249k54407460
asked 13 hours ago
Guy YafeGuy Yafe
4431416
4431416
7
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
12 hours ago
1
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
10 hours ago
add a comment |
7
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
12 hours ago
1
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
10 hours ago
7
7
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
12 hours ago
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
12 hours ago
1
1
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
10 hours ago
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
10 hours ago
add a comment |
3 Answers
3
active
oldest
votes
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 theCAT
name (it is now a cat), but still writesWOOF I am a
, even tough I would have thought that it should call theCat
'svoice
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.
add a comment |
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.
add a comment |
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.
When you say behavior is not portable you need to explain why. The destructor is already virtual.
– SergeyA
12 hours ago
I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.
– Gilles-Philippe Paillé
12 hours ago
Do note there is a virtual destructor in the code in question
– NathanOliver
12 hours ago
@NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.
– Gilles-Philippe Paillé
12 hours ago
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/3.0/"u003ecc by-sa 3.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%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
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 theCAT
name (it is now a cat), but still writesWOOF I am a
, even tough I would have thought that it should call theCat
'svoice
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.
add a comment |
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 theCAT
name (it is now a cat), but still writesWOOF I am a
, even tough I would have thought that it should call theCat
'svoice
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.
add a comment |
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 theCAT
name (it is now a cat), but still writesWOOF I am a
, even tough I would have thought that it should call theCat
'svoice
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.
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 theCAT
name (it is now a cat), but still writesWOOF I am a
, even tough I would have thought that it should call theCat
'svoice
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.
edited 8 hours ago
John Kugelman
249k54407460
249k54407460
answered 12 hours ago
NathanOliverNathanOliver
99.1k16138219
99.1k16138219
add a comment |
add a comment |
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.
add a comment |
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.
add a comment |
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.
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.
answered 12 hours ago
SergeyASergeyA
45.2k53990
45.2k53990
add a comment |
add a comment |
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.
When you say behavior is not portable you need to explain why. The destructor is already virtual.
– SergeyA
12 hours ago
I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.
– Gilles-Philippe Paillé
12 hours ago
Do note there is a virtual destructor in the code in question
– NathanOliver
12 hours ago
@NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.
– Gilles-Philippe Paillé
12 hours ago
add a comment |
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.
When you say behavior is not portable you need to explain why. The destructor is already virtual.
– SergeyA
12 hours ago
I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.
– Gilles-Philippe Paillé
12 hours ago
Do note there is a virtual destructor in the code in question
– NathanOliver
12 hours ago
@NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.
– Gilles-Philippe Paillé
12 hours ago
add a comment |
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.
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.
edited 8 hours ago
answered 12 hours ago
Gilles-Philippe PailléGilles-Philippe Paillé
56210
56210
When you say behavior is not portable you need to explain why. The destructor is already virtual.
– SergeyA
12 hours ago
I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.
– Gilles-Philippe Paillé
12 hours ago
Do note there is a virtual destructor in the code in question
– NathanOliver
12 hours ago
@NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.
– Gilles-Philippe Paillé
12 hours ago
add a comment |
When you say behavior is not portable you need to explain why. The destructor is already virtual.
– SergeyA
12 hours ago
I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.
– Gilles-Philippe Paillé
12 hours ago
Do note there is a virtual destructor in the code in question
– NathanOliver
12 hours ago
@NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.
– Gilles-Philippe Paillé
12 hours ago
When you say behavior is not portable you need to explain why. The destructor is already virtual.
– SergeyA
12 hours ago
When you say behavior is not portable you need to explain why. The destructor is already virtual.
– SergeyA
12 hours ago
I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.
– Gilles-Philippe Paillé
12 hours ago
I meant that some compilers do not behave the same. "Undefined behavior" might be better. I'll edit the answer.
– Gilles-Philippe Paillé
12 hours ago
Do note there is a virtual destructor in the code in question
– NathanOliver
12 hours ago
Do note there is a virtual destructor in the code in question
– NathanOliver
12 hours ago
@NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.
– Gilles-Philippe Paillé
12 hours ago
@NathanOliver That's true. I was mentioning general rules that needs to be respected. I will make it clearer.
– Gilles-Philippe Paillé
12 hours ago
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%2f55711220%2foverriding-an-object-in-memory-with-placement-new%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
7
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
12 hours ago
1
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
10 hours ago