Reputation: 117
I have this code and I'd like to ask - how is it possible to initialize a class object with new int() without getting an exception? When I print the value of the object it prints junk but I still don't understand how this assignment is possible. What exactly happens when you use new int(value)? doesn't it create space for an int and initializes it with value?
class A {
static A* first;
static A* last;
A *prev, *next;
public:
A() : prev(last), next(nullptr) {
cout << "A ctor" << endl;
if (last) last->next = this;
last = this;
if (!first) first = this;
}
virtual ~A() {
if (prev) prev->next = next;
if (next) next->prev = prev;
if (first == this) first = next;
if (last == this) last = prev;
}
static void printAll() {
if (first) cout << *first;
else cout << "list is empty" << endl;
}
friend ostream& operator<<(ostream& out, const A&a) {
a.printSelf();
if (a.next) out << *(a.next);
else out << endl;
return out;
}
virtual void printSelf() const = 0;
};
template<class T>
class B : public A {
T * t;
public:
B(const T& _t) : t(new T(_t)) { cout << "B ctor" << endl; }
virtual ~B() {
cout << "Dtor B" << endl;
cout << *this;
delete t;
}
virtual void printSelf()const override {
cout << *t << ' ';
}
};
A* A::first = nullptr;
A * A::last = nullptr;
int main() {
B<int*>b1 = new int(5);
b1.printSelf(); //prints junk (b1.t value)
cout << endl;
cout << typeid(b1).name() << endl; //prints class B<int*>
}
Upvotes: 1
Views: 181
Reputation: 14865
You are probably looking for explicit
keyword:
Without explicit, the compiler will try implicit conversion between types using the constructor:
class Test
{
public:
Test(int){}
};
Test t = 42;
If this is not supposed to happens, then you can use explicit
(I personally recommend to use it by default on each non-copy single-argument constructor.
class Test
{
public:
explicit Test(int){}
};
Test t = 42; //error here
In your case, T
is a pointer to int
, thus, new int(5)
will generate an integer on heap and return a pointer to it. This is a valid argument for B
.
Looking inside your constructor:
B(const T& _t) : t(new T(_t)) { cout << "B ctor" << endl; }
your receive a _t
which is a pointer to int (e.g. 0xabcd -> 5), and you initialize this->t
with a new pointer to pointer to int, initialized with 0xabcd
. That is:
B(const int*& _t): t(new int*(_t))...
// t is &(0xabcd), *t is 0xabcd, **t is 5
Then printing *t
:
cout << 0xabcd << ' '; // printing the memory address, not the value 5.
You can try this instead:
cout << **t << ' '; // Print 5
But... it's probably better to solve the double allocation and remove the memory leak:
B<int>b1 = 5;
Upvotes: 3