Reputation: 27
Does instantiating classes without handles like this cause memory leaks in C++?
new SomeClass();
What about passing them inside methods?
SomeMethod(new SomeClass())
Do they get deallocated after the method's definition goes out of scope?
It does sound like a stupid question, but as far as I know, they're not going anywhere if they aren't freed.
Upvotes: 2
Views: 127
Reputation: 4474
Yes, you are correct. In default C++, every new
call must be followed by a delete
, otherwise it is a leak. However there are edge cases where new
can be used without a delete
.
One such case is with placement new where memory allocation is handled by yourself. Example:
#include <cstdint>
#include <memory>
#include <iostream>
struct X {
int a;
int b;
};
int main(int argc, char** argv) {
char buffer[256];
X* x1 = new (&buffer[0]) X{1,2};
X* x2 = new (&buffer[8]) X{3,4};
std::cout << "x1: " << x1->a << " " << x1->b << std::endl;
std::cout << "x2: " << x2->a << " " << x2->b << std::endl;
// no leaks since the memory is released when `buffer` is
// deallocated. However it is good practice to call the
// destructor directly
x1->~X();
x2->~X();
}
Produces:
Program stdout
x1: 1 2
x2: 3 4
Godbolt: https://godbolt.org/z/sEPWadcKh
Another case is when a class overrides the operator new as in this example:
#include <cstdint>
#include <memory>
#include <iostream>
static char buffer[32768];
static char* ptr = &buffer[0];
struct X {
int a;
int b;
void* operator new(size_t size) {
void* p = ptr;
ptr += size;
return p;
}
void operator delete(void*) {
// no need to do anything
}
};
int main(int argc, char** argv) {
X* x1 = new X{1,2};
X* x2 = new X{3,4};
std::cout << "x1: " << x1->a << " " << x1->b << std::endl;
std::cout << "xs: " << x2->a << " " << x2->b << std::endl;
// no leaks since the memory is released when `buffer` is
// deallocated. However it is good practice to call the
// destructor directly
x1->~X();
x2->~X();
}
Produces:
Program stdout
x1: 1 2
x2: 3 4
Godbolt: https://godbolt.org/z/jc4r9qbxh
Yet another case is when you use new
with smart pointers like in the case below
#include <cstdint>
#include <memory>
#include <iostream>
#include <boost/intrusive_ptr.hpp>
struct X {
X(int a_, int b_ ) : a(a_), b(b_){
std::cout << "Constructor " << this << std::endl;
}
~X() {
std::cout << "Destructor " << this << std::endl;
}
int a;
int b;
int count = 0;
};
void intrusive_ptr_add_ref(X* x)
{
++x->count;
}
void intrusive_ptr_release(X* x)
{
if (--x->count == 0)
delete x;
}
int main(int argc, char** argv) {
boost::intrusive_ptr<X> x1 = new X{1,2};
boost::intrusive_ptr<X> x2 = new X{3,4};
std::cout << "x1: " << x1->a << " " << x1->b << std::endl;
std::cout << "x2: " << x2->a << " " << x2->b << std::endl;
}
Produces:
Constructor 0xb4b2b0
Constructor 0xb4c2e0
x1: 1 2
x2: 3 4
Destructor 0xb4c2e0
Destructor 0xb4b2b0
Godbolt: https://godbolt.org/z/b7MTfazT9
So although delete
is called on your behalf, you as in the user does not have to call delete
yourself.
Yet another use case is when creating objects for frameworks that manage the lifetime of objects like Qt.
So the answer is really YES, always call delete
after new
but there are plenty of cases in the industry where it is not really necessary.
Upvotes: 3