Deleting a pointer twice in C++ [duplicate] - c++

This question already has answers here:
What is The Rule of Three?
(8 answers)
How to actually implement the rule of five?
(6 answers)
Closed 1 year ago.
I am new to code in C++. So, below code looks pretty decent to me.
#include<iostream>
using namespace std;
class B {};
class A {
public:
B* b;
A() {
cout << "ctor" << endl;
b = new B();
}
~A() {
cout << "dtor" << endl;
delete b;
}
};
void func(A a) {
cout << a.b << endl;
}
int main() {
A a;
cout << a.b << endl;
func(a);
cout << a.b << endl;
}
But I found an issue with this code. When I run this, it gives free(): double free detected in tcache 2 error. I know the cause of this error (it is because dtor is being called 2 times).
One way to solve the problem is, writing a copy constructor for class A where, I create a new B() like this.
A(A const& a) {
cout << "copy ctor" << endl;
b = new B();
*b = *a.b;
}
But if B is a very big class, and hence if I prefer to share b pointer, then how would I avoid this problem?

Related

How does shared_ptr work in c++ without initialization [duplicate]

This question already has answers here:
What will happen when I call a member function on a NULL object pointer? [duplicate]
(6 answers)
Closed 3 years ago.
I was going through shared_ptr and came across this.
class A
{
public:
A() { cout << "In constructor" << endl; }
~A() { cout << "Destructor" << endl; }
void fun() { cout << "In fun... " << endl; }
};
int main()
{
shared_ptr<A> a;
a->fun();
return 0;
}
The output of this is - In fun...
I would like to understand how is this giving above output.
On further experimentation if there is a member variable and being used in this function it throws an SIGSEGV.
class A
{
public:
A() { cout << "In constructor" << endl; }
~A() { cout << "Destructor" << endl; }
void fun() { a = 5 ; cout << "In fun... " << endl; }
int a;
};
int main()
{
// A::fun();
shared_ptr<A> a;
a->fun();
return 0;
}
Above throws SIGSEGV stating this pointer is null.
The code in both cases has undefined behavior because the raw pointer of the shared_ptr pointer is initialized by nullptr.
In the second case the code tried to access memory of the data member a using nullptr.
In the first case the code executed without a failure only due to there is no access to the memory of the object. However the code has undefined behavior because you may not use a null-pointer to access non-static members of a class..

Deleting this pointer from constructor [duplicate]

This question already has answers here:
c++ delete pointer issue, can still access data [closed]
(6 answers)
Closed 3 years ago.
I tried deleting this pointer from constructor, and afterwards when i access private variable through a member function, the variable is fetched correctly.
If I try to delete this again(in constructor or func()), my program crashes. That means this pointer is deleted fine in constructor.
class B
{
int a;
public:
B()
{
std::cout << this;
std::cout << "\nConstructor\n";
delete this;
a = 5;
std::cout << "\n" << this;
}
~B()
{
std::cout << "Destructor\n";
}
void func()
{
std::cout << "\n" << a << " Func\n";
}
};
int main(int argc, char* argv[])
{
B *b = new B();
b->func();
return 0;
}
But calling func() prints correct output. I expected some error due to deleted this. Why the implicit argument of func() is not updated when deleted?
delete this is allowed and just fine. Accessing any members of the class after deleting it however is not allowed and is undefined behavior. Your code appearing to work is one form that UB can take.

Constructor not throwing exception [duplicate]

This question already has an answer here:
C++ constructor not called
(1 answer)
Closed 4 years ago.
In my code below, I wanted to test what would happen if I had an object, that contained another object whose constructor throws exception. But the code below does absolutely nothing. Nothing is printed on the console at all.
class A
{
public:
A()
{
cout << "in A constructor" << endl;
throw "error creating A";
}
~A()
{
cout << "destructing A" << endl;
}
};
class C
{
public:
C()
{
cout <<"in C constructor" << endl;
}
~C()
{
cout << "in C destructor " << endl;
}
};
class B
{
public:
C c;
A a;
B(A a_, C c_): a(a_), c(c_){}
B(){}
};
int main()
{
try{
B b(A, C);
//B b;
}
catch(char const* s)
{
cout <<"catching" << endl;
}
}
If in the try block, I use commented code instead, then it shows fine.
I also tried doing
B b(A(), C());
Still nothing.
This is a function declaration with return type B, name b, and two unnamed arguments of type A and C:
B b(A, C);
The same for
B b(A(), C());
as names can be enclosed by parentheses (to allow grouping, necessary when working with e.g. function pointers etc.), and even names that are left out can be enclosed by parentheses. You can turn it into a variable b of type B by
B b(A{}, C{});
One of the motivation for the curly braces to initialize variables was to disambiguate in such cases. Here, it obviously comes in handy.

C++ destructor called twice with stack allocated compound objects

I have a compound class (instance containing other instance, nor pointer, nor reference).
When the container instance is destroyed, destructor of contained instance is called (I am ok with that, it's logic). But the issue is that if the contained instance is stack allocated destructor is called once again when reaching out of scope.
Is that a coding error or a compiler issue?
What is the cleanest way of fixing it?
Here is my sample:
#include <iostream>
using std::cout;
using std::endl;
class A {
public:
int i;
A(int i_) : i(i_) {
cout << "A(): " << i << endl;
}
~A() {
cout << "~A(): " << i << endl;
}
};
class B {
public:
A a;
int b;
B(const A& a_) : a(a_) {
cout << "B(): " << a.i << endl;
}
~B() {
cout << "~B(): " << a.i << endl;
}
};
int main(void) {
for(int c = 0; c < 3; ++c) {
A a(c+1);
B b(a);
cout << b.a.i << endl;
}
return 0;
}
Output is:
A(): 1
B(): 1
1
~B(): 1
~A(): 1
~A(): 1
A(): 2
B(): 2
2
~B(): 2
~A(): 2
~A(): 2
A(): 3
B(): 3
3
~B(): 3
~A(): 3
~A(): 3
Compiler is gcc 7.3.0
The destructor is only called once per object. What you don't see in your output is that when you construct b, you create a copy of a using the copy constructor (which in your case is compiler-generated). That doesn't produce any output, but of course the destructor of the copy is also called.
If we add output to the copy constructor, we can see what actually happens:
A(const A& a_) : i(a_.i) {
cout << "A(const A&): " << i << endl;
}
The output shows that each A is copied once, leading to the "duplicated" (not really) destructor calls (live demo). If you want to avoid copying the object, look into C++11's std::move, which is explained in depth elsewhere on this site.

C++11: Private member security [duplicate]

This question already has answers here:
Why can I use auto on a private type?
(5 answers)
Closed 9 years ago.
Let's consider the next code:
#include <iostream>
#include "mydemangled.hpp"
using namespace std;
struct A
{
private:
struct B {
int get() const { return 5; }
};
public:
B get() const { return B(); }
};
int main()
{
A a;
A::B b = a.get();
cout << demangled(b) << endl;
cout << b.get() << endl;
}
And the compiler (gcc 4.7.2) yells saying that A::B is private. All right.
So, I change the code:
int main()
{
A a;
cout << demangled(a.get()) << endl;
cout << a.get().get() << endl;
}
and it doesn't yell:
$ ./a.out
A::B
5
Meaning, I can't to create instances of A::B, but I can use it.
So, new change (the key of my question).
int main()
{
A a;
auto b = a.get();
cout << demangled(b) << endl;
cout << b.get() << endl;
}
And output:
$ ./a.out
A::B
5
What is the trouble here, being A::B private (and thus its constructors, copy constructors and so on)?
In general, access controls names or symbols, not the
underlying entities. There are, and always have been, numerous
ways of accessing private members; what you cannot do is use the
name of such a member.
In your examples, you don't use the name, so there is no
problem.