3

I came across a small standard header file <new>. I have probably not seen its direct use before. Here is the g++ version for those who are interested.

Below part is of my interest:

  struct nothrow_t { };
  extern const nothrow_t nothrow;
  /** If you write your own error handler to be called by @c new, it must
   *  be of this type.  */
  typedef void (*new_handler)();
  /// Takes a replacement handler as the argument, returns the previous handler.
  new_handler set_new_handler(new_handler) throw();
  1. How struct nothrow_t and its object nothrow are used by programmers ? Is the object really needed to be extern?
  2. When does new_handler used ?
  3. Why all the operator new/delete are declared in extern C++ block ?
BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 1
    Not a duplicate, but answer to this Q answers some of your Q's: [How should I write ISO C++ Standard conformant custom new and delete operators?](http://stackoverflow.com/questions/7194127/how-should-i-write-iso-c-standard-conformant-custom-new-and-delete-operators/) – Alok Save Nov 22 '12 at 05:34

2 Answers2

5

nothrow_t is used to tell operator new to operate in the backwards-compatible "return null on failure rather than throwing an exception" mode.

That is, if you see code like this:

int * idx = new(std::nothrow) int;

that would be nothrow_t at work. For the relevant sections in the standard start at (as of C++11 N3376) 17.6.4.6 [replacement.functions]/1 and work your way down from there.

To answer your specific questions:

  1. Yes, it really does have to be extern, at least according to 18.6 [support.dynamic]/1, which includes:

    namespace std {
        class bad_alloc;
        class bad_array_new_length;
        struct nothrow_t {};
        extern const nothrow_t nothrow;
        typedef void (*new_handler)();
        new_handler get_new_handler() noexcept;
        new_handler set_new_handler(new_handler new_p) noexcept;
    }
    

    Moreover, 17.6.2.3 [using.linkage]/1 says "Entities in the C++ standard library have external linkage (3.5)". Functions and classes (e.g. get_new_handler and set_new_handler above) don't explicitly need to be annotated to have external linkage because they have external linkage by default.

  2. new_handler is used when the user overrides the default operator new in use by calling set_new_handler. It is just a function pointer type.

  3. Probably because the signatures for operator new are not reserved in C. extern "C++" tells the compiler that it is allowed to do name mangling and other C++ specific things to those functions. This way you can compile one translation unit as C, and one as C++, and link them together in the same binary without worrying that someone in C land defined a function conflicting with the compiler's operator new.
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • +1. Regarding (2); it will be helpful if you can give reference/example. [cplusplus](http://www.cplusplus.com/reference/std/new/set_new_handler/) example is confusing. Also has it to be only for overloaded `new`? I believe it should go well with existing `operator new` also. – iammilind Nov 22 '12 at 05:37
  • @iammilind: I have never used the feature so I'm a bit uncomfortable providing an example at this time, and in the general case I think it is usually a bad idea. There are use cases for it which is why it is in the language but I'd be surprised if more than 0.001% of programs did it. (Even in cases where people want to use custom allocators, they usually override `new` for a specific type; or just make a `std::allocator` implementation rather than overriding global `operator new`) – Billy ONeal Nov 22 '12 at 05:39
  • @iammilind: I don't understand what you mean about "overloaded `new`" versus "existing `operator new`". `set_new_handler` only overrides the global `operator new` implementation. If a there is a type specific `operator new` overload, then that one will be used instead; even if someone calls `set_new_handler` somewhere. – Billy ONeal Nov 22 '12 at 05:42
2

Well, this is really a "read the documentation, please" question. Any good introduction book on C++ should discuss nothrow. For example, Bjarne's "The C++ Programming Language" does, as I recall.

But anyway, you use nothrow to turn std::bad_alloc exceptions into nullpointer results, and you use a new handler to possibly retry a failed allocation.

As a practical matter, remember to put :: in front of new when you use the nothrow feature, and in general when using the global placement new, in order to avoid picking up placement new from classes. Except that placement new should in general be avoided (as the very low level language feature that it is), I would do this even when it does not technically make sense. Just as a good habit.


Example:

#include <iostream>     // std::wcout, std::endl
#include <stdlib.h>     // EXIT_FAILURE, EXIT_SUCCESS
#include <new>          // std::nothrow
using namespace std;

int main()
{
    int* const p = ::new( std::nothrow ) int[0x7fffffff/sizeof(int)];
    if( !p )
    {
        cout << "Allocation failed!" << endl;
        return EXIT_FAILURE;
    }
    cout << "Alles success!" << endl;
    delete[] p;
    return EXIT_SUCCESS;
}

Output on my system:


[D:\dev\test]
> a
Allocation failed!

[D:\dev\test]
> _

Note that the above assumes a 32 bit process :)

Phong
  • 6,600
  • 4
  • 32
  • 61
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • +1 -- note that the above assumes a 32 bit machine + 32 bit process :) (and that `int` has at least 32 bits of storage) – Billy ONeal Nov 22 '12 at 05:36
  • @Billy: thanks, I was going to add that comment, but my mother just got out of bed, and she always demands attention. Anyway, even though you meant well, plase don't *correct my code*. The correction you added (`` -> ``) was ungood. It is not a good idea to use the `` header, since it has some disadvantages and no advantages. It is particularly ungood to change good code to use that header. – Cheers and hth. - Alf Nov 22 '12 at 05:40
  • @Billy: on the other hand, it is incorrect that "`int` has at least 32 bits of storage". It doesn't. `int` has at least 16 bits of storage, and that's it. – Cheers and hth. - Alf Nov 22 '12 at 05:40
  • Is it a good practice to put `::` before `new(nothrow)` or a compulsion? – iammilind Nov 22 '12 at 05:42
  • @Cheersandhth.-Alf: 1.I changed it because this is a C++ question. I would argue that it has the advantage of being consistent with the other headers in the C++ standard library. But okay, I'm not going to change it back. 2. No, your constant `0x7fffffff` is of type `int` and requires 32 bits of storage. The behavior will be undefined (signed integer overflow is undefined) if int is only 16 bits. – Billy ONeal Nov 22 '12 at 05:43
  • @iammilind: i would say so, that it is good practice, but then, i did say so... ;-) others may possibly disagree. as with nearly all questions of good practice. – Cheers and hth. - Alf Nov 22 '12 at 05:44
  • @Billy: oh, you meant for the above program. yes, that `int` has 32 bits of storage, exactly. – Cheers and hth. - Alf Nov 22 '12 at 05:45
  • @Billy: No, the behavior is not undefined for 16-bit `int`, because the type of a hex literal changes depending on the ranges of the built-in types. I.e. there is no fixed type for such a literal. See table 6 in C++11 §2.14.2/2. However, the behavior will be undefined if `size_t` is only 16 bits. I believe that it has had that size on some systems. – Cheers and hth. - Alf Nov 22 '12 at 05:55
  • @Cheersandhth.-Alf: Interesting. I stand corrected. (size_t would be allowed to be 16 bits on a 16 bit system; but I think it is a fair assumption that most code isn't going to run on 16 bit hardware when even most SoCs nowadays are 32 bit machines) – Billy ONeal Nov 22 '12 at 06:18
  • Note that headers like `` are *deprecated*, meaning the standard perspective is to prefer `` over ``. – L. F. Aug 17 '19 at 21:16