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.
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.
Related
I tried to modify an object of A indirectly by allocating 8 bytes using std::allocator. I used <int> specifically, hoping it will return aligned memory for 2 integers. Then I modified an object of A.
Why do I only see A.x=9 in the bitset (towards the end 1001), what happened to A.y=10? Do I need to align the raw pointer returned by std::allocator?
I was expecting the output below:
0000000000000000000000000000100100000000000000000000000000001010
before=0000000000000000000000000000000000000000000000000000000000000000
---------------------
sizeof(A)=8
alignof(A)=4
x: 9 y: 10
---------------------
x: 9 y: 10
after=0000000000000000000000000000000000000000000000000000000000001001
#include <bitset>
#include <iostream>
struct A {
int x;
int y;
A() = delete;
friend std::ostream &operator<<(std::ostream &os, const A &a) {
os << "x: " << a.x << " y: " << a.y;
return os;
}
};
int main(int argc, char **argv) {
std::allocator<int> alloc;
auto raw = alloc.allocate(2);
std::bitset<64> before(*raw);
before.reset();
std::cout << "before=" << before << "\n";
std::cout << "---------------------\n";
std::cout << "sizeof(A)=" << sizeof(A) << "\n";
std::cout << "alignof(A)=" << alignof(A) << "\n";
auto a = reinterpret_cast<A *>(raw);
a->x = 9;
a->y = 10;
std::cout << *a << "\n";
std::cout << "---------------------\n";
std::bitset<64> after(*raw);
std::cout << *a << "\n";
std::cout << "after=" << after << "\n";
return 0;
}
I actually don't see any undefined behviour here.
The actual problem is that you seem to assume that before(*raw) creates a bitset with a snapshot of that memory region. But that is not what happens.
See: https://en.cppreference.com/w/cpp/utility/bitset/bitset
(you call the unsigned long long constructor)
If you simply write (before after):
unsigned long long raw_converted_to_long = *raw;
You see the value is 9 - this is the reason why the bitset is filled with 9.
here is my code snippet:
#include <iostream>
#include <list>
#include <memory>
class A
{
public:
int a = 100;
A()
{
std::cout << "Create A" << std::endl;
}
~A()
{
std::cout << "Release A" << std::endl;
}
virtual void printer() = 0;
};
std::list<std::shared_ptr<A>> arr;
class B : public A
{
public:
int b = 1000;
~B()
{
std::cout << "Release B" << std::endl;
}
void printer() override
{
std::cout << "B's printer" << std::endl;
}
B()
{
std::shared_ptr<A> tmp(this);
arr.push_back(tmp);
(*arr.begin())->printer();
std::cout << "inside B's c'tor test B counts: " << tmp.use_count()
<< std::endl;
}
};
int main(int argc, char const *argv[])
{
std::shared_ptr<B> B_ptr = std::make_shared<B>();
std::shared_ptr<A> A_ptr(B_ptr);
std::cout << "list address: " << (*arr.begin()).get() << std::endl;
std::cout << "test B address: " << B_ptr.get() << std::endl;
std::cout << "test A address: " << A_ptr.get() << std::endl;
std::cout << "list counts: " << (*arr.begin()).use_count() << std::endl;
std::cout << "test B counts: " << B_ptr.use_count() << std::endl;
std::cout << "test A counts: " << A_ptr.use_count() << std::endl;
return 0;
}
My expectation is: A's reference count should be three, but only got 2. I think when I push_back to the list, there should be a temporarily created share_ptr object, even it is get destroyed, the one in list should also pointing to the same address as A_ptr and B_ptr. It turns out that they (those three), did pointing at the same address, but use_count got different results. (*arr.begin()).use_count() is 1, the others are both 2.
Why? Please help.
Ps: I know turning this pointer to share_ptr is stupid operation, but the result doesn't make sense and even disobey the syntax.
My expectation is: A's reference count should be three, but only got 2.
Your expectation is wrong. You only made one copy of the shared pointer, so the use count is 2.
std::shared_ptr<A> tmp(this);
On this line you transfer the ownership of a bare pointer that you don't own into a new shared pointer. Since this was already owned by another shared pointer, the behaviour of the program will be undefined when the two separate owners attempt to destroy it.
Creating a shared pointer from this is possible using std::enable_shared_from_this, but it's not simple.
When running the following code, it seems that the destructor is running twice. I have a theory that this might have to do with an automatic move constructor being added, but I'm not sure how to test this.
#include <iostream>
#include <functional>
struct Structure {
Structure(int n) :
Value(n) {
std::cout << "constructor: " << Value << std::endl;
}
~Structure() {
std::cout << "destructor: " << Value << std::endl;
}
int Value;
};
int main() {
int Init = 4;
std::function<void()> Function = [Instance = Structure(Init)] () {
std::cout << "Value is: " << Instance.Value << std::endl;
};
Function();
Function();
return 0;
}
Output:
constructor: 4
destructor: 4
Value is: 4
Value is: 4
destructor: 4
Is this output correct?
std::function works by copying the callable object you provide. There is no copy-elision here, since your lambda is not an std::function but of an anonymous, unrelated type.
Hence, the two destructors you see are:
The Instance member of the original, temporary, lambda;
The Instance member of the copy of the lambda that was stored into the std::function and lived until the end of main.
Ok, I defined the move and copy constructors manually and also saw errors when I instructed the compiler to delete them in a variant of the code below. Everything seems normal.
Revised code:
#include <iostream>
#include <functional>
struct Structure {
Structure(int n) :
Value(n) {
std::cout << "constructor: " << Value << std::endl;
}
Structure(const Structure& other) :
Value(other.Value) {
std::cout << "copy constructor: " << Value << std::endl;
}
Structure(Structure&& other) :
Value(other.Value) {
other.Value = -1;
std::cout << "move constructor: " << Value << std::endl;
}
~Structure() {
std::cout << "destructor: " << Value << std::endl;
}
int Value;
};
int main() {
int Init = 4;
std::function<void()> Function = [Instance = Structure(Init)] () {
std::cout << "Value is: " << Instance.Value << std::endl;
};
Function();
Function();
return 0;
}
Output:
constructor: 4
move constructor: 4
destructor: -1
Value is: 4
Value is: 4
destructor: 4
Question #1: How can I build a constructor set the value for (R,PoF,PoR)? I am trying to understand how constructor works but I guess I don't quite get it.
Question #2: Can I build destructor in this way, instead of the way I used in my program?
Circle::~Circle()
{
std::cout << "The fence would cost " << SwimmingPool.PerimeterP(r) << std::endl;
std::cout << "The road would cost " << SwimmingPool.AreaP(r) << std::endl;
std::cout << "Present by FF" << std::endl;
}
I just want the cost to come out by itself, but I don't know how should I create destructor to do so.
Here is my full code:
#include "stdafx.h"
#include "iostream"
const double PI = 3.1415926;
class Circle
{
public:
Circle();
double AreaP(int r);
double PerimeterP(int r);
~Circle();
private:
int R;
int PoF;
int PoR;
};
double Circle::AreaP(int r)
{
return ((r + R)*(r + R) - r*r)*PI*PoR;
}
double Circle::PerimeterP(int r)
{
return (r + R) * 2 * PI*PoF;
}
Circle::Circle()
{
int R = 3;
int PoF = 35;
int PoR = 20;
}
Circle::~Circle()
{
std::cout << "Present by FF" << std::endl;
}
int main()
{
int r;
Circle SwimmingPool;
std::cout << "Please input the radius of the Swimming Pool." << std::endl;
std::cin >> r;
std::cout << "The fence would cost " << SwimmingPool.PerimeterP(r) << std::endl;
std::cout << "The road would cost " << SwimmingPool.AreaP(r) << std::endl;
return 0;
}
You have:
Circle::Circle()
{
int R = 3;
int PoF = 35;
int PoR = 20;
}
That function creates three function local variables and sets their values. It does not initialize the members of the class. Change it to:
Circle::Circle() : R(30), PoF(35), PoR(20) {}
Always prefer to initialize in the initializer list instead of setting the values in the body of the constructor.
No, you may not use:
Circle::~Circle()
{
std::cout << "The fence would cost " << SwimmingPool.PerimeterP(r) << std::endl;
std::cout << "The road would cost " << SwimmingPool.AreaP(r) << std::endl;
std::cout << "Present by FF" << std::endl;
}
SwimmingPool is a variable in main. It cannot be used in the destructor. Besides, it does not make sense to print those messages in the destructor. It should simply be
Circle::~Circle()
{
}
Circle::Circle() : R(3), PoF(3), PoR(3) {};
Define the R, PoF, PoR as const int
The destructor must not throw an exception and generally you want it to release resources acquired by the object. Usually not the best place to be outputting stuff to stdout.
Don't use std::endl unless you want to flush the stream. Use '\n' instead.
I want to write a library wrapper class (LibWrap) around a C library that uses malloc/free. To do this I want to use C++'s RAII to allocate and free memory. I used lib_address as a random example address that I would receive from the library. However when defining my memeber variable the destructor that is called somehow has this lib_address.
I would expect the destructor of the member variable created by the default constructor not to know the new address that I am putting into the constructor of my replacement member variable.
#include <stdlib.h>
#include <iostream>
using namespace std;
class LibWrap
{
int j;
int lib_address;
public:
LibWrap(): //default LibWrap
j(0),
lib_address(0)
{
cout << "default LibWrap "<<j <<"\t\t"<<lib_address << "\t" << this<<endl;
}
LibWrap(int f_j): //special LibWrap
j(0),
lib_address(0)
{
j = f_j;
lib_address = rand();
cout << "special LibWrap " << j<<"\t"<< lib_address<< "\t" << this <<endl;
}
~LibWrap()
{
cout << "killing LibWrap " << j<<"\t" <<lib_address <<"\t" << this<< endl;
}
int g()
{
return j;
}
};
class A
{
int i;
LibWrap b;
public:
A(): //default A
i(0)
{
cout << "default A\t"<<i << endl;
}
A(int f_i)://special A
i(0)
{
i = f_i;
cout << "special A\t"<<i << endl;
b = LibWrap(10);
}
~A()
{
cout << "killing A\t"<<i << endl;
}
void p()
{
cout <<"Test values: "<< i<< "," << b.g() << endl;
}
};
int f()
{
//A a; a.p();
cout << "variable\t\tlib_address\treal_address" << endl;
A a = A(1);
cout << "End" << endl;
//a.p();
}
int main()
{
f();
}
Running this code I would expect to get the following result:
variable lib_address real_address
default LibWrap 0 0 0xbfef2e28
special A 1
special LibWrap 10 1804289383 0xbfef2df8
killing LibWrap 10 1804289383 0xbfef2df8 --would expect kiling LibWrap 0 0 0xbfef2e28
End
killing A 1
killing LibWrap 10 1804289383 0xbfef2e28 --would expect killing LibWrap 10 1804289383 0xbfef2df8
b = LibWrap(10);
This does not initialize b. b has already been initialized as part of constructing A. What you're doing is creating a temporary LibWrap and copying that temporary into b. Then, you're destroying that temporary LibWrap (which is where the extra destructor call with the lib_address comes from).
The temporary LibWrap is where the "0xbfef2df8" address comes from. The b variable is the "0xbfef2e28" address. That's why you're getting them in that order.