#include <iostream>
using namespace std;
class teacher{
private:
int Tnum;
public:
teacher(){
Tnum = 0;
}
teacher(int n){
cout << "creating teacher"<<endl;
Tnum = n;
}
~teacher(){
cout << "destroying teacher" << endl;
}
};
class student: public teacher{
private:
int Snum;
public:
student(){
Snum =0;
}
student(int n){
cout << " creating student"<<endl;
Snum = n;
}
~student(){
cout << "destroying student"<<endl;
teacher t(1);
cout << "teacher created"<<endl;
}
};
int main(){
teacher t(20);
student s(30);
}
You showed an example that compiles. What happens?
It behaves just like an object created in any other function, and it will be destroyed once it goes out of scope.
From 12.4p8 we find that:
After executing the body of the destructor and destroying any automatic objects allocated within the body [...]
This confirms that creating objects in the body of the destructor is legal.
But, be careful! It could hurt you if the constructors of those objects throw exceptions, because destructors are non-throwing and encountering an exception would result in the termination of the application.
Related
I meet a course programming problem, which asks me to initialize the A a using passing by reference (initialize the A a in the func). How can I call A's constructor by A's reference?
#include <iostream>
using namespace std;
class A
{
public:
int x;
A()
{
cout << "default constructor" << endl;
x = 1;
}
A(int x)
{
cout << "constructor with param = " << x << endl;
this->x = x;
}
~A() {
cout << "destructor" << endl;
}
void print() {
cout << x << endl;
}
};
void fun(A& a)
{
a.A::A(10); // error!
return;
}
int main()
{
A a;
fun(a);
a.print();
return EXIT_SUCCESS;
}
There is a background of this problem. The teacher want us to replicate the NRVO(named return value optimization) result.
#include <iostream>
using namespace std;
class A
{
public:
int x;
A()
{
cout << "default constructor" << endl;
x = 1;
}
A(int x)
{
cout << "constructor with param = " << x << endl;
this->x = x;
}
~A() {
cout << "destructor" << endl;
}
void print() {
cout << x << endl;
}
};
A fun() {
A a = A(10);
return a;
}
int main()
{
A a = fun();
return EXIT_SUCCESS;
}
default g++ compiler:
constructor with param = 10
destructor
if we close the NRVO:
g++ test.cpp -fno-elide-constructors
constructor with param = 10
destructor
destructor
destructor
destructor
The teacher want us to replicate the NRVO(named return value optimization) result by passing by reference.
The syntax a.A::A(10); is incorrect.
Constructor is used to create an object of a class, you cannot call it on an already existing object. Even a constructor cannot be explicitly called. It is implicitly called by the compiler.
From general-1.sentence-2:
Constructors do not have names.
Thus, you cannot call a constructor explicitly. The compiler will automatically call the constructor when an object of that class-type is created.
You can not, not like this.
A reference always points to an initialized object. So you already failed before you called the function. The "return" argument is already initialized. And you can't initialized an initialized value again, not legally.
You can cheat by calling
std::construct_at(&a, 10);
For it to really reflect NRVO you could have something like this:
void fun(A *a)
{
std::construct_at(a, 10);
}
union UninitializedA {
std::byte uninitialized[sizeof(A)];
A a;
};
int main()
{
UninitializedA u;
fun(&u.a);
u.a.print();
u.a.~A();
return EXIT_SUCCESS;
}
I am trying to understand why my code doesn't use destructor of class Name. In fact I write two classes. First one called Name and a second called Person that have a pointer to object Name. What I don't understand is why the program doesn't called to the destructor of Name, because I think when I write "new" I create a new object so it has to call to the destructor of class Name before closing program.
Can you explain what wrong in my understanding. Thanks !
class Name
{
private:
string name;
public:
Name(string name) : name(name) { cout << "Hello " << name << endl; }
~Name() { cout << "See you soon " << name; }
};
class Person
{
private:
Name* myname;
public:
Person(string name) { myname = new Name(name); }
~Person() { cout << "Exit" << endl; }
};
int main()
{
Person("Marc");
Person("Alex");
}
You are creating a memory leak here, because you create a new instance of Name here
Person(string name) { myname = new Name(name); }
but you never delete it. This is the reason why the destrcutor of Name is never called.
To avoid this you can use an std::unique_ptr or an std::shared_ptr, which will automatically handle the lifetime of such an object.
std::unique_ptr<Name> myname;
Person(string name) { myname = std::make_unique<Name>(name); }
An alternative is to delete the object in your destructor, but in C++ you should avoid direct handling of dynamic raw pointers.
#include <iostream>
#include <memory>
class Name
{
private:
std::string name;
public:
Name(std::string name) : name(name) { std::cout << "Hello " << name << std::endl; }
~Name() { std::cout << "See you soon " << name << std::endl; }
};
class Person
{
private:
std::unique_ptr<Name> myname;
public:
Person(std::string name) { myname = std::make_unique<Name>(name); }
~Person() { std::cout << "Exit" << std::endl; }
};
int main(int argc, char **argv)
{
Person("Marc");
Person("Alex");
return 0;
}
As myname object in Person's class is a pointer. For every pointer there must be a delete statement to deallocate the memory.
Replace Person's class Destructor as:
~Person() {
cout << "Exit" << endl;
delete myname;
}
I have a base class named A containing a string type parameter.
Class B is derived from A.
I define class C have parameter A* a, and
assign it to B.
In the main function, I cannot get the string value of the base class as it became blank when b deconstructs.
I want it to output:
"Hello!"
"Hello!"
end
But the output is:
"Hello!"
end
Here is my code:
class A {
public:
string str;
};
class B : public A {
public:
B(string _str) {
str = _str;
}
};
class C {
public:
A *a;
public:
void printOut() {
B b("Hello!");
a = &b;
cout << a->str << endl;
}
};
int main() {
C c;
c.printOut();
cout << c.a->str << endl;
cout << "end" << endl;
return 0;
}
How can I deal with it?
Correct, because B b("Hello!"); goes out of scope, c.a is now a dangling pointer that will cause undefined behaviour upon being dereferenced. If you want it to outlive the scope you could allocate it on the heap instead :
class A {
public:
string str;
};
class B : public A {
public:
B(string _str) {
str = _str;
}
};
class C {
public:
A *a;
public:
void printOut() {
B* b = new B("Hello!");
a = b;
cout << a->str << endl;
}
};
int main() {
C c;
c.printOut();
cout << c.a->str << endl;
cout << "end" << endl;
delete c.a;
return 0;
}
This gets messsy real fast though because you have to track the memory allocated yourself and call delete appropriately, consider redesigning or using smart pointers.
Why are you storing an A* ? You know that doesn't work, so stop doing it.
Make a copy of the A object, or a copy of the string it contains, and stop trying to do something silly.
class A {
public:
string str;
};
class B : public A {
public:
B(string _str) {
str = _str;
}
};
class C {
public:
string str;
public:
void printOut() {
B b("Hello!");
str = b.str;
cout << str << endl;
}
};
int main() {
C c;
c.printOut();
cout << c.str << endl;
cout << "end" << endl;
return 0;
}
I'm getting an error in my code I don't get at all.
Here is my code:
MyClass.h
#include "MyClass.h"
int i = 1;
MyClass::MyClass()
{
}
MyClass:~MyClass()
{
}
MyClass.cpp
#pragma once
class MyClass
{
public:
MyClass();
virtual ~MyClass();
int i;
protected:
private:
};
main.cpp
#include<iostream>
#include "MyClass.h"
using namespace std;
int main()
{
MyClass myObject = *new MyClass();
cout << myObject.i << endl;
cin.get();
}
I just get some random number. Any help here?
You are not initializing i in your class, your constructor should look something like this:
MyClass::MyClass() : i(1)
{}
It also looks like you have a few typos, this:
MyClass myObject = *new MyClass();
should be:
MyClass *myObject = new MyClass();
and this:
cout << myObject.i << endl;
should be:
cout << myObject->i << endl;
Although, as chris says the simpler option would be as follows:
MyClass myObject ;
cout << myObject.i << endl;
The i that you set to 1 is not a member of the class. It is a static variable outside of any class.
Once i belongs to you class, you need to initialize it inside its constructor
#include "MyClass.h"
// int i = 1; <-- not here
MyClass::MyClass()
{
i = 1; // here
}
and to initialize your object in main function just do something like that:
int main()
{
// MyClass myObject = *new MyClass(); <-- myObject is not a pointer
MyClass myObject;
cout << myObject.i << endl;
cin.get();
}
Couple things wrong: First, you're redeclaring i in MyClass.cpp, try assigning to it in the constructor instead:
//int i = 1;
MyClass::MyClass() : i(1)
{
}
Second, the way you're declaring your object in your main() is wrong too. Either you do:
int main()
{
MyClass* myObject = new MyClass();
cout << myObject->i << endl;
cin.get();
delete myObject;
}
if you want a pointer to a dynamically allocated object or just
int main()
{
MyClass myObject;
cout << myObject.i << endl;
cin.get();
}
if you want an object allocated on the stack.
I learned that one of the motivation for copy constructor using is to avoid of the follow crash in the program -
#include <iostream>
using namespace std;
class Employee {
public:
Employee(int ID,char const * name){...};
~Employee(){...};
// Methods
void Print();
private:
// members
int m_ID;
char* m_name;
};
void MyFunc(Employee emp) {
cout << "in MyFunc \n ";
}
int main() {
Employee One(1,"Garen Torosian");
// calling copy constructor
MyFunc(One);
cout << "In the end of main \n";
// Here the program crashes!
return 0;
}
as you can see the program should be crash before the return 0; , but when I run that program it works fine and terminated ok , why ?
Edit : In this case the program indeed crash -
// Employee.h
#include <iostream>
using namespace std;
class Employee {
public:
Employee(int ID,
const char* name);
~Employee();
// Methods
void Print();
private:
// members
int m_ID;
char* m_name;
};
// Employee.cpp
#include "Employee.h“
Employee::Employee(int iID, const char *name){ // Ctor
cout << "Constructor called" << endl;
m_ID = iID;
m_name = new char [strlen(name) +1];
strcpy(m_name, name);
Print();
}
void Employee::Print() { // Print
cout << "ID: " << m_ID << ",Name:” << m_name
<< " ,Address(pointer):0x" << hex << (int) m_name<< endl;
}
Employee::~Employee() { // Dtor
cout << "Destructor called"<<endl;
Print();
delete [] m_name;
m_name=NULL;
}
void MyFunc(Employee emp) {
cout << "in MyFunc \n ";
}
int main()
{
Employee One(1,"Eli Rachamim");
// calling copy constructor
MyFunc(One);
cout<< "In the end of main \n“;
// Here the program crashes!
return 0;
}
If you d-tor is like
~Employee(){ delete[] name; }
and you alloc memory for your char* pointer, and you have no copy c-tor, than copy c-tor generated by compiler, that do memberwise-copy, will be called when you copy object. So, there will be double-free, that in most cases give you memory dump (in real calling destructor to already destructed object is UB and calling delete[] on already deleted object is also UB). But if you don't work with memory - copy c-tor, generated by compiler works well.
EDIT.
So, your second example demonstrates call of d-tor to allready destructed object and also double-free.
Why do you think it should crash?
C++ has the unfortunate feature of supplying an automatically-generated copy-constructor if you don't provide one, and your MyFunc() doesn't really do anything that would get screwed by that auto-generated copy.