14

I have two blocks of code about new[] and delete[]:

1)

#include <string>

int main()
{
  std::string *p = new std::string[0];
  delete[] p;

  return 0;
}

2) In this case, I merely change std::string to int

int main()
{
  int *p = new int[0];

  delete[] p;

  return 0;
}

My question is:

Why the first program crashes with the following message (in linux environment):

Segmentation fault (core dumped)

But the second program works well without any error?

EDIT

compiler: g++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2

I just use g++ without any argument to compile it.

If it is a compiler bug, should they crash or not according to the standard?

Yishu Fang
  • 9,448
  • 21
  • 65
  • 102
  • 1
    It doesn't crash here. Which compiler are you using (with exact version) and how are you compiling it? – amaurea Oct 31 '12 at 13:19
  • 1
    Crash with g++ (4.7 & 4.8), doesn't crash with clang. I guess it is a g++ bug. – kennytm Oct 31 '12 at 13:21
  • 1
    The program shouldn't crash. The reason why it crashes is that the people who made your compiler made a mistake somewhere. The only thing you can do is to rewrite to avoid the bug, or use another compiler :/ The easiest by far is probably the former. Do you really need an array of length zero? – amaurea Oct 31 '12 at 13:37

1 Answers1

13

This should be a gcc bug. That the whole new[] expression is ignored and p becomes uninitialized, and then we delete[] an uninitialized pointer which crashes. If we compile the program with -Wall it will warn you that

warning: ‘p’ is used uninitialized in this function

which is clearly wrong. The expression new X[0] is well-defined in both C++03 and C++11 (§5.3.4/7), and this works correctly in clang, so the only logical conclusion is that it's a gcc bug.


The elimination-of-new[] bug only exists when the type to be constructed has any non-trivial constructor. And the segfault happens the type has a destructor, because the delete[] will then need to dereference that uninitialized pointer. Therefore, it crashes for std::string but not int, because int is trivial and std::string is not.


This can be worked around by using an intermediate variable, such that the expression cannot be evaluated to 0 directly:

size_t length = 0;
std::string* p = new std::string[length];
// ...
delete[] p;
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • I am surprised the hack works... On liveworkspace I have 3 behaviors: original OP code (warning + crash), this work-around (no warning, no crash), using `size_t const length = 0;` (warning, no crash). I *love* gcc... – Matthieu M. Oct 31 '12 at 14:31