3

I understand the placement new operator allows to construct object at a particular/specific memory location. So i tried this;

#include <iostream>
#include <new>

using namespace std;

struct Any {
    int x;
    string y;
};

int main() {

    string mem1[1];
    int mem2[5];

    Any *p1 = new (mem1) Any;
    Any *p2 = new (mem2) Any;

    p1->y = "Hello";
    //p2->x = 20;

    cout << p1->y << endl;
    //cout << p2->x;

    return 0;
}

What I realized is, I can set a string to a location that I've set aside to hold exactly 1 string but i can't do same for an integer like so;

int mem2[1];
Any *p2 = new (mem2) Any;
p2->x = 20;

I get a buffer overflow error even though it manages to show me the value I placed in that location which is 20;

enter image description here

Why?

Also, with my full code shown above, I have set aside 2 different memory locations to hold the 2 objects which makes p1->y print without any problems. But when i reduce this location

int mem2[5]; to any number below 5 which i think has nothing to do with the location where I placed the string and try to print the string, I get a segmentation fault error. Why >= 5? Does it have to do with memory available?

Is there a way to check if using the placement new operator to place an object at a specific memory location was successful?

WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
  • Looks like you'll have some serious memory alignment issues when placement new'ing a `Any` into an array of `string` or `int` – AndyG Nov 08 '16 at 18:58
  • 2
    You have to make sure that an `Any` object fits in the space you try to put it in. `mem1` is definitely too small. Another problem is that the destructor for a string is called at the end of its scope, so you will have to restore `mem1` before the end of `main`. – Bo Persson Nov 08 '16 at 19:04
  • Also, most compilers are smart enough to transform `x = 20; cout << x;` into just `cout << 20;`, and not bother to write anything to `x`. So that is not a very good test for if it is working. – Bo Persson Nov 08 '16 at 19:10
  • Placement new is *guaranteed* to be successful, unless the constructor throws an exception or you provoke undefined behavior. If the constructor throws you can just `catch` it, and undefined behavior can't be detected kind of by definition. – Mark Ransom Nov 08 '16 at 19:21
  • @BoPersson I don't get any error that says `Any` object didn't fit into `mem1` so it runs fine. It's when i reduce 'mem2` to any number below `5` that i get errors trying to print what's in `mem1`. That's why I'm confused! – Richardson Ansong Nov 08 '16 at 19:22
  • @NanaOsaberima there is no guarantee at all that if you override memory you would notice it, so you need to understand how it works rather than guess. – Slava Nov 08 '16 at 19:25

1 Answers1

4

You have sets of Undefined Behavior in your code. First of all, there's no guarantee that the declaration string mem[1]; sets aside enough memory to contain an abject of type Any....

Secondly, even if the first had adequate memory to hold such object, the destructor of the array string mem[1]; will still run at the end of main, but you've overwritten that array with something else, hence your program should at best case, crash.

You may want to use a POD type, like char mem1[sizeof(Any)] to store the object, that way you are sure of mem1 being capable enough to store Any, and you'll have no issues with destructor of mem1 being called at the end of main()

Again, you may want to explore a standard facility for this kind of thing, std::aligned_storage

WhiZTiM
  • 21,207
  • 4
  • 43
  • 68
  • That is why i asked if there's a way to check if **placement new** was successful – Richardson Ansong Nov 08 '16 at 19:13
  • @NanaOsaberima, the primary job of placement new is to call the constructor... And it's the only way to make the C++ runtime create an object in a specific location. Your question is like asking how to know if an object's constructor was successfully called when declared on the stack. – WhiZTiM Nov 08 '16 at 19:30
  • 2
    Placement new is guaranteed to succeed if and only if: the constructor being called doesn't throw an exception **and** you have all rights to the **entire** memory required to store such object – WhiZTiM Nov 08 '16 at 19:37