Do I need to overload delete if I have operator T *()? - c++

If I have a template class A which holds a pointer, and A has an implicit conversion operator which will return that pointer, do I need to, or should I, define a delete operator for A, if I intent to apply delete to objects of this class?

You only need to define operator delete if you define operator new -- in which case you pretty much must do so.
That doesn't mean that something won't need to delete your A*s -- but you don't need to define any operators for that, it will work by default.

I believe that you've got something like the following:
template <typename T>
struct A {
T * t;
operator T* () { return t; }
};
An you intend to "apply delete to objects of this class", so by that I'm assuming you mean:
void foo ()
{
A<int> * p = new A<int>;
delete p; // Applying 'delete'
}
If this is the case, then the call to delete correctly destroys the object and frees the the memory allocated by the use of 'new' on the previous line and the answer to your question is 'no'.
Because you have declared a conversion operator to a pointer, it is possible to use delete on an object of type A<int> (a opposed to A<int>*). The use of delete will be applied to the result of calling the conversion operator:
void foo ()
{
A<int> a;
a.t = new int;
delete a; // Same as: delete a.operator T*()
}
Basics of how delete works:
The expression delete p, does two different things. Firstly, it calls the destructor for the object pointed to by p and then it frees the memory. If you define an operator delete member for your class then it will be that function which will be used by delete p to free the memory.
In general, you only define those operators when you want to control how the memory for dynamic objects of that class should be allocated or freed.

If your class owns this pointer, it should delete it in its destructor. Be aware that overloading this operator may be confusing, because the usual approach to obtain a pointer to an object is by taking its address.

Does you class A really need to define an implicit conversion operator? Maybe have a simple T* get() const method that returns the pointer, like the boost and std smart pointer do. Implicit conversion can cause all kinds of trouble.

Related

C++ custom delete

Let's say we have the following code:
class MyType
{
public: int x;
}
MyType* object = new MyType();
delete object;
Is there a possible to check if object has specific value of x before deletion?
For example, if object.x is odd number, the object should not be free from memory after delete is called. In a few words to make a custom delete for this class where we can choose when the object can be free at operator delete call.
What is the real issue you are trying to solve?
To begin with, this Q&A is a good lesson to the common scenario in C++ of:
The language allowing you to do something, but just because you can doesn't mean you should.
These scenarios are commonly run into when trying to solve an XY problem.
In this particular case, instead of trying to overload operator delete (solving the Y problem, to much confusion of the clients of MyType) you are likely looking for something entirely different (the X problem), say a resource manager that take responsibility of MyType resources w.r.t. if and when they should be deleted (or not), based on e.g. object traits (such as oddness of a data member). See e.g. #Ayxan Haqverdili's answer for a minimal example.
A look at theoretically solving the misidentified Y problem
Don't do this, ever, for this kind of use case.
You can overload operator delete (as well as operator delete[]), by defining it as a static member function of the class for which you want to overload it (lookup precedence by lexical scope). As pointed out in the comments, whilst overloading the usual deallocation functions is legal, trying to conditionally allow for it to be called more than once is not:
struct MyType final {
int x;
static void operator delete(void *p) {
if (static_cast<MyType *>(p)->x % 2 == 1) {
::operator delete(p);
}
}
};
int main() {
MyType *object = new MyType{42};
delete object; // Not DEALLOCATED.
// Underlying object DESTRUCTED, however.
// Extremely confusing.
++(object->x);
delete object; // UB: destructor for underlying object called twice.
}
as per [expr.delete]/6 [emphasis mine]:
If the value of the operand of the delete-expression is not a null pointer value and the selected deallocation function (see below) is not a destroying operator delete, the delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted.
As a second attempt (emphasis: don't ever go down this road), we could avoid the destructor being called (only calling it conditionally) by overloading and abusing the (new as of C++20) class-specific destroying deallocation functions:
#include <iostream>
#include <new>
struct MyType final {
int x;
static void operator delete(MyType *p, std::destroying_delete_t) {
if (p->x % 2 == 1) {
p->~MyType();
::operator delete(p);
}
}
~MyType() {
std::cout << "\ndtor";
}
};
int main() {
MyType *object = new MyType{42};
delete object; // Neither deallocated nor underlying object destructed.
++(object->x);
delete object; // Destructed and deallocated.
}
Afaict this program is well-formed, but it does abuse the new destroying delete overloads. Clang does emit a -Wmismatched-new-delete warning, which is typically a hint for UB, but it may be inaccurate here.
Anyway, this seems like a good place to stop the fruitless journey of addressing this particular Y problem.
Yes:
if (object->x % 2 == 1)
delete object;
Note that raw pointers should be used rarely and with a lot of care.

How to properly overload global new function to create objects

I've seen a few places that show how to overload the global new function for allocations. What I would like to do is to have any call to 'new' call my function, which simply wraps the C++ standard 'operator new' and tracks memory usage. But I have a problem of not knowing how to construct the object because the type of the object is not available in the function:
void* operator new (std::size_t size)
{
// I don't know what to construct
}
struct MyClass{ int members[8];}
new MyClass; // I'd basically like to wrap the standard 'new' function allocator.
You are not supposed to construct an object inside of an overloaded operator new, only allocate raw memory of the requested size and return a pointer to it. The object’s constructor will be called on the returned memory after the operator new exits.
A new expression calls operator new specifying the size of the type, then calls the type’s constructor on that memory, and then returns a pointer to the object that was created.
Thus, an expression like new MyClass in your example is roughly equivalent (not exactly) to this:
//MyClass *cls = new MyClass;
void *mem = :: operator new (sizeof(MyClass));
MyClass *cls = static_cast<MyClass*>(mem);
cls->MyClass();
And the converse is true for the delete expression, which calls the type’s destructor, and then calls operator delete to deallocate the raw memory, eg:
//delete cls;
cls->~MyClass();
:: operator delete (cls);
It seems you're looking for a Factory function. A factory is a dedicated function (or even a class) that produced instances of a class.
E.g.
#include <memory>
struct MyClass { int members[8]; };
std::unique_ptr<MyClass> MyClassFactory() {
auto inst = std::make_unique<MyClass>();
// assign some stuff to members
return inst;
}

Is new T() equivalent to `mem = operator new(sizeof(T)); new(mem)T`?

Basically, my question is whether the following code is valid.
void* mem = operator new(sizeof(T));
T* instance = new(mem) T;
delete instance;
If it isn’t, I’d be curious to know whether there is a way to split allocation and initialization for an object that is going to be deleted through delete obj;.
This does appear to be valid, as long as T is not an array type, and is not a class with a custom operator delete visible from its scope which is incompatible with the operator new you invoke.
[expr.delete]/2 says the operand of delete may be "a pointer to a non-array object created by a previous new-expression". The new-expression grammar syntax symbol does include the placement new syntax, and [expr.delete] doesn't say the previous new-expression needs to be a non-placement variety. And any new-expression including a placement new is considered to "create" an object.
The operator new allocation function and operator delete deallocation function involved do need to match up. operator new(sizeof(T)) will normally call the global ordinary allocation function, but to be more sure you can write ::operator new(sizeof(T)). The deallocation function is looked up in the scope of class T, so a static operator delete(void*); in a class could break this.
You might want to consider exception safety, though. A straight T* p = ::new T; is actually more equivalent to:
void* mem = ::operator new(sizeof(T));
T* p;
try {
p = ::new(mem) T;
} catch (...) {
::operator delete(mem, sizeof(T));
throw;
}
Your code is given almost exactly in the same form, as an explicit example, in the C++ standard:
21.6.2.3 Non-allocating forms [new.delete.placement]
void* operator new(std::size_t size, void* ptr) noexcept;
Returns: ptr.
Remarks: Intentionally performs no other action.
[ Example: This can be useful for constructing an object at a known
address:
void* place = operator new(sizeof(Something));
Something* p = new (place) Something();
— end example ]
Add a delete, after that, and you get what you wrote in your question.

Returning a different class pointer by overloaded operator new in a class

Suppose i have this sample code:
class A
{
public:
static void* operator new(size_t sz);
private:
int xA;
float yA;
};
class B : public A
{
private:
int xB;
float yB;
};
void* A::operator new(size_t sz)
{
void* ptr = (void*)new B();
return ptr;
}
int main()
{
B* b = (B*) new A();
// Use b ..
delete b;
return 0;
}
Here the constructors will be called in that order (tested in VS2012):
A constructor
B constructor
A constructor
The first two constructors calls are because of the new B() in the overloaded operator new function.
But then the A constuctor will be called again on the pointer returned by the function because the overloaded operator new is supposed to return a pointer to free memory (without creating the object), so the constructor is called again.
If i use the pointer b in this example, is this undefined behaviour?
The code you posted has endless recursion, since you call
A::operator new from within A::operator new; class B
inherits the operator new from A.
Beyond that, you lie to the compiler, which results in undefined
behavior. After new A, you have a pointer to an object whose
type is A. You can legally convert its address to a B*, but
all you can do with that B* is convert it back to an A*;
anything else is undefined behavior.
And it's not clear what you're trying to achieve with the new
B in A::operator new. The compiler will consider any memory
returned from an operator new as raw memory; in this case, it
will construct an A object in it, and from then on out, all
you have is an A object. Any attempt to use it as a B
object is undefined behavior. (And of course, if you actually
need to destruct the B created in A::operator new, you can't
because you've overwritten it.
Finally: you don't have to declare operator new as static;
it implicily is, and it's idiomatic not to write the static in
this case. Similarly, when assigning the results of new B to
a void*, the conversion is idiomatic, and it is idiomatic not
to make it explicit. (It's also best to avoid the C style
casts, since they hide too many errors.)
In general , operator new() should not CREATE an object, it should create space for an object. Your code will overwrite a B object with an A object, and then use it as a B object, and yes, that would be "undefined" (probably covered in the docs under "casting an object to a different type that it wasn't originally created as).
This may appear to work in this particular case, but if the constructor of B is more complex (e.g. there are virtual functions in B), it would immediately fail to work correctly.
If you want to allocate memory for an object, you could do:L
void* A::operator new(size_t sz)
{
void* ptr = (void*)::new unsigned char[sz];
return ptr;
}
Now you are not calling two different constructors for the same object!
The contract of operator new is just the memory allocation, the initialization is done later by the new-expression (by calling the constructor) or by program code if you call the operator directly.
What you are trying to do cannot be done, not like that. You could redesign to use a factory member function that would return a pointer to a B object, for example...

placement new signature

void someCode()
{
char memory[sizeof(Foo)];
void* place = memory;
Foo* f = new(place) Foo();
}
and the signature of new placement operator
void * operator new(size_t, void *p)
{
return p;
}
I don't get how a constructor could be bind to void *p since a constructor doesn't return any values ?
EDIT:
the following code for instance doesn't compile :
struct A{};
void f(void * p)
{
}
int main()
{
f(A());
std::cin.ignore();
}
The problem here is that C++ new is confusing:
there is the operator new, which you can overload and is in charge of allocating raw memory
there is the new expression (such as new A(5)) which under the covers first call the corresponding operator new overload and then performs the construction
Note that you have no say as to how the construction is performed: you supplied the type and the constructor parameters, the language does the rest, and there is no way to change this behavior.
Therefore, when you overload/override operator new, you are only affecting the raw memory allocation. The full syntax of the new expression can clear things up:
new (somepointer) A(5)
^~~~~~~~~~~~~ ^~~~
The first part is the list of arguments passed to operator new, on top of the size of the object (always passed). The second part corresponds to the constructor call. If there is no parameter to be passed to new (apart from the size which you don't control) then the first part may be omitted yielding the typical form new A(5).
You are free to overload new as much as you want, for example:
new (alignof(A)) A(5);
will call an operator new overload accepting a size_t as supplementary argument (representing the necessary alignment for the type):
void* operator new(size_t size, size_t alignment);
note: the first argument (size) is always there.
So, placement new is just a fancy overload in its own right:
void* operator new(size_t, void* p) { return p; }
There is not much interest in such an operator (it does nothing), however it helps maintaining a consistent syntax and allows you a way to specify where to build an object via using the new expression so that it is not necessary to create another syntax to allow such operation.
Constructor called after operator new executed. You posted not equivalent code. Equvalent would be
struct A
{
constructor (void* this);
}
int main ()
{
A a = A::constructor(operator new ());
}
It is not c++, just pceudocode
I think that the source of your confusion is an assumption that new(place) Foo(); is a single operation; it is not. Here is what's going on:
A placement new operator is called to allocate memory
A constructor is called to initialize the allocated memory
The first call needs to return the value (a void*). It is a block of memory suitable to store your object. The second call is a constructor. It gets the value from the placement new operator as its hidden this parameter, and performs its regular initialization tasks on it.