Placement new With Overloaded Ordinary new Operator - c++

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?

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);

Related

no matching operator delete found; memory will not be freed if initialization throws an exception

I have made a BaseObject class that overrides the new (and delete) operators, so I can log memory as it is created and destroyed during the lifecycle of my application, making it easy for me to spot any unreleased memory.
However, I am getting the following errors when I compile (but it runs fine):
resourcemanager.h(36): warning C4291: 'void *BaseObject::operator new(size_t,const char *,int)': no matching operator delete found; memory will not be freed if initialization throws an exception
baseobject.h(8): note: see declaration of 'BaseObject::operator new'
My BaseObject class looks like this:
class BaseObject
{
public:
void* operator new(size_t size, const char* file, int line);
void* operator new[](size_t size, const char* file, int line);
void operator delete(void* ptr);
void operator delete[](void* ptr);
};
#define MY_NEW new(__FILE__, __LINE__)
#define MY_DELETE delete(__FILE__, __LINE__)
From what I read on the internet, the problem is due to the fact that the overridden delete operators need matching signatures. So in this case, it should work if I added "const *char file, int line" to the delete operators. But then I run into another problem as I cannot call delete on any objects since it is not finding a matching delete operator (it must now take file and line as input). Using the MY_DELETE macro above does not work in this case as delete cannot use parameters like that.
Pretty much at a loss here.
EDIT:
The solution was not immediately obvious. Adding overridden delete functions with the same extra parameters as the new functions was not enough since this yielded a problem with there being "no non-placement delete operator". This in turn could be solved by adding a non-placement delete operator. So, the class looks like this now (and it is working):
class BaseObject
{
public:
void* operator new(size_t size, const char* file, int line);
void* operator new[](size_t size, const char* file, int line);
// Placement delete functions, matching overridden new functions
void operator delete(void* ptr, const char* file, int line);
void operator delete[](void* ptr, const char* file, int line);
// Non-placement delete functions
void operator delete(void* ptr);
void operator delete[](void* ptr);
};
From cppreference https://en.cppreference.com/w/cpp/language/new :
If initialization terminates by throwing an exception (e.g. from the
constructor), if new-expression allocated any storage, it calls the
appropriate deallocation function: operator delete for non-array type,
operator delete[] for array type. The deallocation function is looked
up in global scope if the new-expression used the ::new syntax,
otherwise it is looked up in the scope of T, if T is a class type. If
the failed allocation function was usual (non-placement), lookup for
the deallocation function follows the rules described in
delete-expression. For a failed placement new, all parameter types,
except the first, of the matching deallocation function must be
identical to the parameters of the placement new. The call to the
deallocation function is made the value obtained earlier from the
allocation function passed as the first argument, alignment passed as
the optional alignment argument (since C++17), and placement_params,
if any, passed as the additional placement arguments. If no
deallocation function is found, memory is not deallocated.
So the matching signature for delete in your case is:
strip away size
put void* ptr in its place
repeat the parameters passed to operator new.
This leads to:
class BaseObject
{
public:
void* operator new(size_t size, const char* file, int line);
void* operator new[](size_t size, const char* file, int line);
void operator delete(void* ptr, const char* file, int line);
void operator delete[](void* ptr, const char* file, int line);
};
Off-topic: abstract is not a keyword in C++ and this should be a compile error. To make a class abstract, define a function as pure virtual (by putting = 0 as its definition).

Static member placement delete signature?

I have a project that tightly controls what and how can allocate memory. I have a base class for things that may be allocated on a heap, with static overloads for operator new and operator delete and their array variants. These work perfectly without any warnings at all.
There's an ultimate base class for everything that allows placement new only:
class Object
{
public:
static void* operator new(size_t, void*);
static void* operator new[](size_t, void*);
static void operator delete(void*, void*);
static void operator delete[](void*, void*);
};
The implementations are trivial and in the corresponding .cpp file. operator news return the pointer, operator deletes don't do anything.
When I compile this under VS2015, using new (ptr) DerivedFromObject() generates the following warning. Exception handling is set to /EHa.
warning C4291: 'void *Object::operator new(std::size_t,void *)': no matching operator delete found; memory will not be freed if initialization throws an exception
I've tried messing around with the signatures: adding noexcept, adding size_t to operator delete but nothing seems to work. What's the correct form of static member placement operator delete?
It seems that I need to declare operator deletes in every derived class to get rid of the warning.

Difference between "new" operator and "new" function [duplicate]

This question already has answers here:
Difference between 'new operator' and 'operator new'?
(8 answers)
Closed 8 years ago.
Interview question: what's the difference between "new" operator and "new" function?
I answered there is no difference, that they run the same code, but interviewer kept needling me like that was the wrong answer.
Is it the wrong answer? Or was the interviewer just playing games with me?
If it's the wrong answer, what's the right answer?
I continued that the "new" operator could be overloaded if you needed a custom allocation, but then he wanted to know how to overload it. Of course I didn't have that answer, having never had the need, but I told him I could look it up in 10 minutes (which is never the right answer in an interview).
So anyhow, having done some research on "new" operator vs. "new" function and not seeing any really satisfying answers, I thought I'd ask the specific question.
The new operator and operator new are not the same thing.
The new operator calls an operator new function to allocate memory, and then, depending on the type allocated and the syntax used, initializes or calls a constructor on the allocated memory. In other words, operator new forms only a part of the operation of the new operator.
operator new is the function called to allocate memory by the new operator. There's a default implementation of operator new which can be replaced, which is not the same thing as overloading. operator new can also be implemented for a particular type to handle allocations only of objects of that type, or operator new can be overloaded and the overload can be selected by using the placement new form of the new operator.
The default implementations of operator new can be replaced by defining functions with the following signatures:
void *operator new(std::size_t size);
void *operator new(std::size_t size, const std::nothrow_t&);
void *operator new[](std::size_t size);
void *operator new[](std::size_t size, const std::nothrow_t&);
When you provide a replacement or overload for operator new you should provide corresponding operator delete functions:
void operator delete(void* ptr) noexcept;
void operator delete(void* ptr, const std::nothrow_t&) noexcept;
void operator delete[](void* ptr) noexcept;
void operator delete[](void* ptr, const std::nothrow_t&) noexcept;
To provide an overload of operator new for use with the placement form of the new operator you can add additional arguments (the nothrow versions of operator new and operator delete do this).
struct my_type {};
void *operator new(std::size_t size, const my_type&);
void operator delete(void *ptr, const my_type&);
new (my_type()) int(10); // allocate an int using the operator new that takes a my_type object
There is no 'placement delete' form of the delete operator. The overload of operator delete is provided because if an error occurs during the initialization/construction of the memory (e.g., the constructor called by the new operator after operator new has been called) the corresponding operator delete is called if it exists before re-throwing the exception. Otherwise operator delete is not called and the memory leaks when the exception is thrown.
Basically:-
Function: "operator new"
class Example
{ public:
void* operator new( size_t );
}
"new operator":
Example* eg = new Example();
I continued that the "new" operator could be overloaded if you needed
a custom allocation
You are almost right.
new is a keyword for an operator, which is used for memory allocation.
Why is this an operator ?
On need basis, it can be overloaded as a function both at global scope or class scope (but NOT namespace scope!). This wouldn't have been possible if it was a function.
The difference is in how they function. The initial allocation part is, per standard I believe, the same. That is, using syntax new vs operator new() explicitly is very much the same. The difference, is using new initializes or constructs the new object. There is also 3 different versions of ::operator new() and there is various syntaxes to utilize them as well (i.e., placement new).
There is no new function. My guess is that they wanted you to say that one of these allocated the memory (the standard uses allocator function, function new operator and new operator for it) and that the other used the first to allocate memory, then called the constructor (the standard uses new expression) and the deallocator function (aka function delete operator or delete operator) to free the memory if the constructor exited with an exception.

Questions about operator new() and operator delete()

Consider the following code and the questions below:
/*
* GCC 4.4
*/
#include <iostream>
using namespace std;
class A {
public:
void* operator new(size_t s) {
cout << "A::operator new(size_t) called\n";
}
void operator delete(void* p) {
cout << "A::operator delete(void*) called\n";
}
void* operator new(size_t s, A* p) {
cout << "A::operator new(size_t, A*) called\n";
}
void operator delete(void* p, size_t s) {
cout << "A::operator delete(void*, size_t) called\n";
}
};
void* operator new(size_t s) {
cout << "::operator new(size_t) called\n";
}
void operator delete(void* p) {
cout << "::operator delete(void*) called\n";
}
void* operator new(size_t s, A* p) {
cout << "::operator new(size_t, A*) called\n";
}
void operator delete(void* p, size_t s) {
cout << "::operator delete(void*, size_t) called\n";
}
int main() {
A* p1 = new A(); // See question 1.
delete p1; // See question 2.
A* p2 = new (p1) A(); // See question 3.
delete p2; // See question 4.
}
The questions below might seem redundant somehow. However, what I am trying to distinguish is what is defined by the C++ standard rules from what is defined by the implementation.
operator new(size_t) will be used in any case (taken from A or from the global
namespace, be it default or not). This is OK.
Now try to remove void* A::operator new(size_t) {} only: why does the compiler gives:
error: no matching function for call to ‘A::operator new(unsigned
int)’
note: candidates are: static void* A::operator new(size_t, A*)
Connot the compiler pick up ::operator new(size_t) from the global
namespace?
Why is operator delete(void*) preferred to operator delete(void*, size_t)
(when both of those versions are present in the same namespace where operator delete (void*) is taken from)?
Why will not the code compile if I remove void* A::operator new(size_t, A*),
although there is the same version of the operator defined in the global namespace?
error: no matching function for call to ‘A::operator new(unsigned int,
A*&)’
note: candidates are: static void* A::operator new(size_t)
Why does the compiler still prefer
operator delete (void*), although A::operator new(size_t, A*) has been used
for getting p2?
Let's imagine some scenarios. First off, the following always works:
A * p1 = ::new A;
::delete p1;
A * p2 = ::new (addr) A; // assume "void * addr" is valid
p2->~A();
The global expressions always use the corresponding operators from the global namespace, so we're fine. Note that there is no "placement-delete" expression. Every placement-constructed object must be destroyed explicitly by calling the destructor.
Next up, suppose we write:
A * p3 = new A;
delete p3;
This time round, the allocation function operator new(size_t) is looked up in the A's scope first. The name exists, but if you remove the correct overload, you have an error. (This answers Q1 and Q3.) The same goes for operator delete(). There's no particular reason why the one-parameter version ((void *)) is preferred over the two-argument version ((void *, size_t)); you should just have one of the two. (Note also that there's no global version of the two-argument function.)
Finally, let us revisit placement-new expressions. Since there is no placement-delete expression, your final line of code is an error (undefined behaviour): You mustn't delete anything that wasn't obtained through a default-new expression. If you define a placement-new allocation function, you should also define the matching deallocation function. This function will only be called automatically on one specific situation, though: If a placement-new expression new (a, b, c) Foo; causes the constructor to throw an exception, then the corresponding deallocation function is called. Otherwise, since all placement-construction is manual, you will typically only call the placement deallocation function manually (and often never at all, because it rarely does any actual work).
The typical scenario might be something like this:
void * addr = ::operator new(sizeof(Foo)); // do real work
Foo * p = new (addr, true, 'a') Foo; // calls Foo::operator new(void*, bool, char);,
// then calls the constructor Foo::Foo()
// in case of exception, call Foo::operator delete(addr, true, 'a')
p->~Foo();
Foo::operator delete(addr, true, 'a'); // rarely seen in practice, often no purpose
::operator delete(addr); // do real work
To come full circle to the opening code example, note that the standard demands that the global ::operator delete(void *, void *) do nothing. That is, global placement-new is required to need zero clean-up.
As to your first and third question, it IMO works like that:
Because you didn't use ::new, the compiler tries to find a new operator in the A class.
It finds one, but it cannot find the proper overload, so it fails.
If you explicitly state ::new, it shouldn't have any problem. The compiler only goes to the global namespace if it cannot find the specialized version of the new operator in the class.
From the standard: § 5.3.4,
9. If the new-expression begins with a unary :: operator, the allocation function’s name is looked up in the
global scope. Otherwise, if the allocated type is a class type T or array thereof, the allocation function’s
name is looked up in the scope of T. If this lookup fails to find the name, or if the allocated type is not a
class type, the allocation function’s name is looked up in the global scope.
An object does not remember how it was created; placement delete is only used when the corresponding placement new throws, otherwise the regular delete operator is used.

C++ class member functions that use dummy parameters

I know that you can use a dummy "int" parameter on operator++ and operator-- to override the postfix versions of those operators, but I vaguely recall something about a dummy parameter that you could declare on a destructor. Does anyone know anything about that, and if so, what that dummy parameter did?
This was in my old Turbo C++ tutorial books, which I read when I was a teenager (i.e. a long time ago), so I might be completely misremembering it. That was also very early C++, before it was standardized, so it's possible that it was something Turbo C++-specific.
You're possibly thinking of the placement and nothrow forms of operator delete, which have the signatures:
void operator delete(void *, void *) throw();
void operator delete(void *, const std::nothrow_t&) throw();
void operator delete[](void *, void *) throw();
void operator delete[](void *, const std::nothrow_t&) throw();
These are never called during normal operation, but would be used in the case where the constructor for an object being constructed with placement new throws an exception. Generally you don't have to define them, since the compiler already called the destructor(s) on the dead object's bases and members, and for placement new there's no memory to be freed. But can exist if you are overloading placement new and need a corresponding operator.
The second argument is not really used, and just distinguishes the signature for the ordinary:
void operator delete(void *)
These aren't special dummy arguments the way the operator++ ones are, though. They're just an instance of the general rule that call to new with extra arguments, such as:
obj = new(x,y,z) Object(a,b,c)
will generate implicit code to clean up from constructor errors that passes those same additional arguments to the operator delete, which will function (approximately) like:
void *raw = operator new(sizeof(Object), x,y,z)
try {
obj = new(raw) Object(a,b,c);
} catch(...) {
operator delete(raw,x,y,z);
throw;
}
Either you are misremembering, or you should try to forget it. Destructors don't have parameters, return types and they shouldn't throw exceptions.
I swear I've heard the same thing, but the C++ FAQ seems to say that there is no such form.
Perhaps you are thinking of placement new?
class MyClass { /* ... */ };
char * raw_mem = new char [sizeof (MyClass)];
pMyClass = new (raw_mem) MyClass;
// ...
pMyClass-->(~MyClass());
delete[] raw_mem;
You're not crazy. I have definitely seen an int parameter in a destructor before. Using HP's compiler on OpenVMS, I compiled a sample program show below. The list of symbols does include an destructor with an int parameter. I can only guess this is compiler specific.
$ create foo.cxx
class foo
{
~foo() {}
};
$ cxx foo.cxx
$ type [.CXX_REPOSITORY]cxx$demangler_db.
CX3$_ZN3FOOD1EV31GNTHJ foo::$complete$~foo()
CX3$_ZN3FOOD2EV30KQI3A foo::$subobject$~foo()
CX3$_ZN3FOOD9EV36HH9SB foo::~foo(int)
CXXL$_ZDLPV void operator delete(void *)