12

I have an object of type MyType that, for SSE reasons, needs to be 16-byte aligned. So, I wrote an allocator and overloaded the new operators. Methods in MyType:

inline static void* operator new(size_t size) {
    awesome::my_allocator<MyType,16> alloc;
    return alloc.allocate(size);
}
inline static void* operator new[](size_t size) { return operator new(size); }
inline static void operator delete(void* ptr) {
    awesome::my_allocator<MyType,16> alloc;
    alloc.deallocate(reinterpret_cast<MyType*>(ptr),0); //last arg ignored in my impl
}
inline static void operator delete[](void* ptr) { operator delete(ptr); }

Now, for cache-locality reasons, I need to copy-construct an instance into a particular piece of 64-byte-aligned memory:

void MyType::copy_into(uint8_t* ptr) const {
    new (reinterpret_cast<MyType*>(ptr)) MyType(*this);
}

GCC tells me:

error: no matching function for call to ‘MyType::operator new(sizetype, MyType*)’

ICC tells me:

error : function "MyType::operator new" cannot be called with the given argument list
1>              argument types are: (unsigned __int64, MyType *)

As I understand it, the placement new operator is provided by the C++ implementation (or possibly by <new>, which I also tried #includeing?) and simply returns its argument (new makes memory available, and placement new is the programmer saying that the given memory is available).

Curiously, the error does not occur when the (ordinary!) new operators defined above are not in the class. Indeed, MyOtherType, which doesn't define them, works just fine.

Question: what's going on? How should I fix it?

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
geometrian
  • 14,775
  • 10
  • 56
  • 132
  • Perhaps overload the new to take 2 params - operator new(size, align) - so that normal, 1 param news aren't affected. This might get around the compiler complaining by letting it use the built in type. throw vs nothrow overloading might be causing some issues as well. – Michael Dorgan Oct 07 '15 at 18:32
  • Does all that happens in one translation unit? – Lapshin Dmitry Oct 07 '15 at 18:34
  • Placement new is usually used for "placing an object in already allocated memory" perhaps you need to overload placement new operator to coincide with your implementation as well? – AJG85 Oct 07 '15 at 18:36
  • @AJG85 You [cannot overload placement new](http://stackoverflow.com/a/3677129/688624): _"§18.4.​1.3 Placement forms These functions are reserved, a C++ program may not define functions that displace the versions in the Standard C++ library."_ – geometrian Oct 07 '15 at 18:41
  • Oh well, so much for that idea then ;-( – AJG85 Oct 07 '15 at 18:53
  • Side point: `copy_into()` could check that the given memory is 16-byte aligned. Too bad it can't check that the given memory is large enough. – Jerry101 Oct 07 '15 at 19:23

1 Answers1

9

Since you have defined operator new in your class, you need to use the global new to use the placement version of it.

#include <new>

...

::new (reinterpret_cast<MyType*>(ptr)) MyType(*this);
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Confirmed that this fixes the problem. As I understand it, there was an overload of `new` in the current namespace, and so it didn't check the global namespace to find the overload (placement `new`) that would have worked? – geometrian Oct 07 '15 at 18:51
  • I wouldn't say "in the current namespace". I would say "in the `class` itself". There are two steps involved in matching a function call - name lookup and overload resolution. If the name is found in a class or the enclosing namespace, then the lookup ends. If the lookup results in multiple functions, only then overload resolution comes into play. – R Sahu Oct 07 '15 at 18:59