2

I'm looking at the following code:

// operator new example
#include <iostream>     // std::cout
#include <new>          // ::operator new

struct MyClass {
  int data[100];
  int kk;
  MyClass(int ea) : kk(ea) {std::cout << "constructed [" << this << "]\n";}
};

int main () {

  std::cout << "1: ";
  MyClass * p1 = new MyClass(1);
      // allocates memory by calling: operator new (sizeof(MyClass))
      // and then constructs an object at the newly allocated space

  std::cout << "2: ";
  MyClass * p2 = new (std::nothrow) MyClass(2);
      // allocates memory by calling: operator new (sizeof(MyClass),std::nothrow)
      // and then constructs an object at the newly allocated space

  std::cout << "3: ";
  new (p2) MyClass(3);
      // does not allocate memory -- calls: operator new (sizeof(MyClass),p2)
      // but constructs an object at p2

  // Notice though that calling this function directly does not construct an object:
  std::cout << "4: ";
  MyClass * p3 = (MyClass*) ::operator new (sizeof(MyClass));
      // allocates memory by calling: operator new (sizeof(MyClass))
      // but does not call MyClass's constructor

  delete p1;
  delete p2;
  delete p3;

  return 0;
}

And I have two questions:

  • Is the object 2 destroyed when executing the line

    new (p2) MyClass(3);
    

that should construct the object 3 in the object 2's allocated space?

  • The line

    MyClass * p3 = (MyClass*) ::operator new (sizeof(MyClass));
    

also works without the ::, what's the purpose of the scope resolution operator used without a class/namespace before it?

David G
  • 94,763
  • 41
  • 167
  • 253
Johnny Pauling
  • 12,701
  • 18
  • 65
  • 108

2 Answers2

3

Firstly, no, the second object's destructor is not called. A new object is just initialized in its place. If you like, you can explicitly call the destructor of the object with p2->~MyClass(); before you reuse its memory.

Secondly, the purpose of using :: to qualify the allocation function is to make sure it comes from the global namespace. The standard implicitly defines two overloads of operator new for all translation units, and if you include <new>, you get a few extras. All of these are defined in the global namespace (not in std). It's possible to overload operator new for classes (simply provide them as member functions), so qualifying with :: makes sure the global version is used instead.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
2

Answer1: The object located at p2's lifetime ends when you reuse it's memory for a new object. It won't have its destructor run so it's not "destroyed" cleanly, although with only POD members and no user-declared destructor, in this case it makes no difference.

Answer2: Using :: forces the lookup for operator new to only consider operator new declared at global scope. In the scope which you are calling operator new, there is no other operator new that would be considered in any case, so it makes no difference.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656