-6

I am trying to figure out the C++ memory allocation mechanism. I understand the difference between operator new() and the new expression.

But as I found here, the prototypes of operator new() and operator new[]() are almost identical, and the default implementations of operator new[]() should simply invoke the corresponding version of operator new().

My questions are:

  1. If we can simply use operator new() functions to allocate any size of memory and use the memory as an array, what is the purpose of operator new[]()?
  2. I tried this piece of code:

    struct MyClass {
        MyClass() { cout << this << "::MyClass()" << endl;}
        ~MyClass() { cout << this << "::~MyClass()" << endl;}
    };
    
    int main()
    {
        MyClass *ptr = (MyClass *)::operator new[]( sizeof( MyClass) * 3);
        new (ptr) MyClass;
        new (ptr+1) MyClass;
        new (ptr+2) MyClass;
        delete[] ptr;
        return 0;
    }
    

    It printed out following messages before it crashed:

    0x562ecf758e70::MyClass()
    0x562ecf758e71::MyClass()
    0x562ecf758e72::MyClass()
    0x562ecf758e90::~MyClass()
    0x562ecf758e8f::~MyClass()
    0x562ecf758e8e::~MyClass()
    0x562ecf758e8d::~MyClass()
    0x562ecf758e8c::~MyClass()
    0x562ecf758e8b::~MyClass()
    0x562ecf758e8a::~MyClass()
    0x562ecf758e89::~MyClass()
    0x562ecf758e88::~MyClass()
    0x562ecf758e87::~MyClass()
    0x562ecf758e86::~MyClass()
    0x562ecf758e85::~MyClass()
    0x562ecf758e84::~MyClass()
    0x562ecf758e83::~MyClass()
    0x562ecf758e82::~MyClass()
    0x562ecf758e81::~MyClass()
    0x562ecf758e80::~MyClass()
    0x562ecf758e7f::~MyClass()
    0x562ecf758e7e::~MyClass()
    0x562ecf758e7d::~MyClass()
    0x562ecf758e7c::~MyClass()
    0x562ecf758e7b::~MyClass()
    0x562ecf758e7a::~MyClass()
    0x562ecf758e79::~MyClass()
    0x562ecf758e78::~MyClass()
    0x562ecf758e77::~MyClass()
    0x562ecf758e76::~MyClass()
    0x562ecf758e75::~MyClass()
    0x562ecf758e74::~MyClass()
    0x562ecf758e73::~MyClass()
    0x562ecf758e72::~MyClass()
    0x562ecf758e71::~MyClass()
    0x562ecf758e70::~MyClass()
    *** Error in `/home/alec/.cpp-run/1/a.out': free(): invalid pointer: 0x0000562ecf758e68 ***
    

    Why did delete[] try to destruct 30 objects which didn't exist and was out of the memory allocated by operator new[]()? Also, why did it crash?

Bo Persson
  • 86,087
  • 31
  • 138
  • 198
  • 1
    You say there's no single article/blog post on that subject on the web to date? – Marcin Orlowski Dec 22 '17 at 05:07
  • 1
    Read a [good C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) – Passer By Dec 22 '17 at 05:08
  • 1
    What _are_ you doing? My suggestion is for you to not worry about this, stop using pointers, and just use normal objects. Use `MyClass c` if you want a single object, and `std::vector v` if you want a container. Guessing at code is not going to improve you, just start reeeaaaally simple. – Tas Dec 22 '17 at 05:13
  • 1
    Possible duplicate of [int \*array = new int\[n\]; what is this function actually doing?](https://stackoverflow.com/questions/5776529/int-array-new-intn-what-is-this-function-actually-doing) –  Dec 22 '17 at 05:22
  • 1
    Also: [Why should C++ programmers minimize use of 'new'?](https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new) –  Dec 22 '17 at 05:23
  • The reason for the three constructor calls should be obvious - the three `new` expressions each invoke the constructor. The `delete [] ptr` in your code has undefined behaviour since `ptr` is not the result of `new []` expression. There is more to the working of a `new []` expression (e.g. `x = new X [5]`) then calling `operator new []()`. – Peter Dec 22 '17 at 08:27

1 Answers1

1

On question 1). Even though the default versions of operator new() and operator new[]() do the same thing, a program can override operator new[] and make if behave differently. It's a customization point.

On Part 2).

There is a footnote in the standard saying

218) It is not the direct responsibility of operator new[] or operator delete[] to note the repetition count or element size of the array. Those operations are performed elsewhere in the array new and delete expressions. The array new expression, may, however, increase the size argument to operator new[] to obtain space to store supplemental information.

So while new Myclass[3] must store the 3 somewhere so that delete[]can find it, apparently ::operator new[]( sizeof( MyClass) * 3) does not. At least not in the place where delete[] expects it.

So it seems like delete[] happens to find some other number and goes on to destroy non-existent objects until it hits a wall.

Bo Persson
  • 86,087
  • 31
  • 138
  • 198