3

According to C++ Standard, operator new should throw std::bad_alloc(); when allocation fails.

To test this behavior I came up with the following code:

try
{
    for (;;)
    {
        Big* p = new Big;
        if (0 == p)
        {
            printf("nullptr");
            break;
        }
    }
}
catch (std::bad_alloc&)
{
    printf("exception");
}

The problem is, unexpectedly, I get nullptr everytime I run this on my Windows Mobile 2003 (Windows CE 4.2).

The compiler is Microsoft (R) C/C++ Optimizing Compiler Version 14.00.60131 for ARM so I think it is not the case of compiler being non-compliant with The Standard.

I also tried to manually throw std::bad_alloc() inside given try block (and succeeded so the catch part should trigger in case of failing new). Another thing was to set_new_handler() but that didn't work either. In case it is important, my Big has the size of 10MB.

So can you please tell me what I am missing? Why don't I get std::bad_alloc?

Edit 1: I am not looking for how to overcome this but for the reason why it happens in the first place.

Edit 2: I've simplified the program as much as I could, in my journey to debug new, and the disassembly output I got is:

        int* p = new int[10];
00011010  mov         r0, #0x28 
00011014  bl          00011040       <---- here is the call to operator new
00011018  str         r0, [sp, #0xC] 
0001101C  ldr         r3, [sp, #0xC] 
00011020  str         r3, [sp, #4] 
00011024  ldr         r3, [sp, #4] 
00011028  str         r3, p 

        operator new:
00011040  ldr         r12, [pc]           <---- 
00011044  ldr         pc, [r12]           <----  what are those?
00011048  andeq       r3, r1, r0          <----  is it just that?
0001104C  andeq       r1, r1, r4, lsr #11 <----  nothing else to be seen...     
00011050  streqd      r2, [r1], -r0       <----   

Shouldn't there be any system calls? Shouldn't it be more complicated? Can anyone help with investigating this?

sthlm58
  • 1,142
  • 1
  • 9
  • 28
  • Possibly poor standards compliance because exceptions are seen to be two expense for low performance systems. – 111111 Dec 05 '11 at 17:00
  • Assuming `Big` doesn't have an overloaded `new` operator, it's definitely non-conformance. Try it with `struct Big2 { char big[10*1024*1024]; };` just to be certain. You could consider using `new (std::nothrow) Big` instead, just to remind you that's what behavior you're getting. – Steve Jessop Dec 05 '11 at 17:02

1 Answers1

3

This sounds a lot like the behaviour of MSVC6.0 which isn't surprising given by the age of the platform. You can read more about it here.

MSDN Magazine September 2003 (ctrl-f for bad_alloc)

you could always override the new operator for Big but I would advise against it, just accept that it isn't very good implementation, and continue to try and catch for std::bad_alloc in case you port your code to a better platform.

I don't usually advocate macro's but you could whirl one up that checks if null and throws bad_alloc, this can but quickly then be remove if you port your code. (an inline function might do as well but really sometime an ugly fix for an ugly problem is what is required).

template<PointerType>
inline void good_alloc(PointerTpye ptr) //throws std::bad_alloc
{
 #if BAD_COMPILER //MSVC version number?
     if(ptr==null)
     {
         throw std::bad_alloc; 
     }
 #else
     //do nothing
 #endif
}
Eugene Sh.
  • 17,802
  • 8
  • 40
  • 61
111111
  • 15,686
  • 6
  • 47
  • 62
  • Actually making `operator new()` throw can be achieved by providing a `new` handler - that's done with `set_new_handler()`. – sharptooth Dec 06 '11 at 07:16