2

Option A:

T * address = static_cast<T *>(::operator new(capacity * sizeof(T), std::nothrow));

Option B:

T * address = static_cast<T *>(std::malloc(capacity * sizeof(T)));

Context:

template <typename T>
T * allocate(size_t const capacity) {
    if (!capacity) {
        throw some_exception;
    }
    //T * address = static_cast<T *>(std::malloc(capacity * sizeof(T)));
    //T * address = static_cast<T *>(::operator new(capacity * sizeof(T), std::nothrow));
    if (!address) {
        throw some_exception;
    }
    return address;
}

std::malloc is shorter, but ::operator new is clearly C++ and it's probably implemented in terms of std::malloc. Which one is better / more idiomatic to use in C++.

João Pires
  • 927
  • 1
  • 5
  • 16
  • 3
    Have a look at [std::aligned_storage](http://en.cppreference.com/w/cpp/types/aligned_storage). – François Andrieux Sep 27 '17 at 18:50
  • @FrançoisAndrieux: std::aligned_storage doesn't allocate memory – geza Sep 27 '17 at 19:09
  • 3
    @geza That's true. The point of my comment was to suggest allocating instances of `std::aligned_storage` instead of raw memory. The example shows that we know the memory should be large enough to hold some number of objects of type `T`. It's the portable solution. – François Andrieux Sep 27 '17 at 19:13
  • @FrançoisAndrieux - [malloc](http://man7.org/linux/man-pages/man3/malloc.3.html) is defined to already allocate memory "*suitably aligned for any built-in type*". Similarly, `operator new` is [defined](http://eel.is/c++draft/expr.unary#expr.new-11) as: "*The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type*". – rustyx Sep 27 '17 at 19:16
  • @FrançoisAndrieux: I see. Now it is more clear what you wanted to say :) – geza Sep 27 '17 at 19:17
  • 1
    @FrançoisAndrieux: isn't `std::aligned_storage` mainly for non allocated things? Does `operator new` use information about the type it's allocating? For example, does it use alignment information when allocating the storage? – geza Sep 27 '17 at 19:24
  • @geza no operator new doesn't know what type it is allocating and so it can't return different alignments for different objects except based on what it knows from the size of the object (eg if all 8 byte objects need at most 8 byte alignment then it is free to align to 8 in that case, even if larger object might need 16 byte alignment). In practice this means that new and malloc actually just always align to some "big enough" alignment which works for all types with standard alignment. – BeeOnRope Sep 27 '17 at 19:34
  • @BeeOnRope: yep, that's what I know about this too. So here, `std::aligned_storage` doesn't give us anything more than `new char[size];`, does it? – geza Sep 27 '17 at 19:35
  • @geza - I don't actually see how `std::aligned_storage` could be used to implement the `allocate()` function above at all, since you pass `Len` as a (compile-time) template argument, but `allocate` is taking a (runtime) function argument. In general, it seems like `std::aligned_storage` might give more guarantees than operator `new`: the former seems to guarantee that the storage is suitably aligned for _any_ type with size up to `Len` (with the default `Align` value) while operator new only guarantees alignment for objects with "fundamental alignment." – BeeOnRope Sep 27 '17 at 19:53
  • In practice though, I don't see how `std::aligned_storage` with default `Align` can satisfy it's "any object" guarantee in the presence of over-aligned types (which might live in other compilation units) since they could in principle have arbitrarily large alignments. – BeeOnRope Sep 27 '17 at 19:57
  • @geza - I asked specifically about the `std::aligned_storage` behavior [over here](https://stackoverflow.com/questions/46457386/how-can-stdaligned-storage-expose-correctly-aligned-storage-for-any-object). – BeeOnRope Sep 27 '17 at 21:24

1 Answers1

2

If at all possible, you should prefer to allocate memory in a type-safe way. If that's out of the question, prefer Option A, operator new(size_t, std::nothrow) because:

  • Operators new and delete can be overridden legally (this can be useful in custom allocator / leak detection scenarios).
  • Can have an alternative allocator to deal with low memory (set_new_handler).
  • Is much more C++.

The only reason to prefer malloc / free is if you want to optimize reallocations with realloc, which isn't supported by operator new / delete (realloc is not a simple free+malloc).

rustyx
  • 80,671
  • 25
  • 200
  • 267