#include <iostream>
using namespace std;
class foo
{
private:
static int cnt; // number in memory
static int nextid; // the next id number
public:
int id; // not shared - each object has it's own
foo()
{
cnt++; // update the counter of alive foos
id = nextid++; // assign an id
cout << "foo # " << id << " is alive " << endl;
}
~foo()
{
cnt--;
cout << "foo # " << id << " is dead " << endl;
}
void stats()
{
cout << "I am foo number " << id << endl;
gstats();
}
static void gstats()
{
cout << "Objects currently alive: " << cnt << endl;
cout << "Total number ever created: " << nextid << endl;
}
foo( foo &f)
{
cnt++; // update the counter of alive foos
id = nextid++; // assign an id
cout << "foo # " << id << " is alive and copied from " << f.id << endl;
}
};
int foo::cnt = 0;
int foo::nextid = 0;
void dmy1( foo a )
{
cout << "called dmy1 ( by value) id is " << a.id << endl;
}
void dmy2( foo &a)
{
cout << "called dmy2 (by reference) id is " << a.id << endl;
}
int main(void)
{
foo::gstats();
foo f1, f2;
f1.stats();
dmy1(f2);
foo::gstats();
}
This is the code my professor gave me to practice C++ static code.
But when I run this program, I have a question.
Objects currently alive: 0
Total number ever created: 0
foo # 0 is alive
foo # 1 is alive
I am foo number 0
Objects currently alive: 2
Total number ever created: 2
foo # 2 is alive and copied from 1
called dmy1 ( by value) id is 2
foo # 2 is dead
Objects currently alive: 2
Total number ever created: 3
foo # 1 is dead
foo # 0 is dead
This is the output.
But I don't know the reason why this function is called
Could you explain?
foo( foo &f)
{
cnt++; // update the counter of alive foos
id = nextid++; // assign an id
cout << "foo # " << id << " is alive and copied from " << f.id << endl;
}
And, also, Why static void gstats(){ ~ } is called after destructing foo #2 ?
Ok, i try to explain what happens
First it is showed no objects exist at this point
foo::gstats();
Now f1 and f2 are declared and created on stack (2 objects alive)
foo f1, f2;
f1.stats is called and shows the current state
f1.stats();
f2 is passed by value (copyed on stack with copy constructor call foo( foo &f)) to dmy1 (3 objects alive)
dmy1(f2);
after leaving dmy1 it's scope (stack variables used by it) is destroyed and f2's copy gets it's destructor called (2 objects alive) and this status is displayed
foo::gstats();
Then main() is left and it's scope is destroyed as well and f1 and f2's destructors are called (0 objects alive)
The function is called copy constructor. It's called because you pass the object f2 to dmy1 by value and a copy of the object is constructed. If you would change the object a inside dmy1, f2 would stay the same - because you implicitly constructed a copy when you passed the parameter in by value.
foo#2 is destructed when you exit the function dmy1, because it's only alive inside that function. So it's destructed before calling gstats.
It is copy constructor, as it was said. But copy constructor should have been declared like this:
foo(const foo &f)
{
...
}
Related
I am the following code
struct Me {
Me(Me* a) { std::cout << "Processing " << a << std::endl; }
};
int main() {
Me a(&a);
std::cout << "Created obj in " << &a << std::endl;
Me* ak = new Me(ak);
std::cout << "Created obj in " << ak << std::endl;
delete ak;
return 0;
}
and the output was
Processing 0x7ffdbd7f0607
Created obj in 0x7ffdbd7f0607
Processing 0x5653b66b5110
Created obj in 0x5653b6d35120
As you can observe that first 2 line of output was fine as the address passed to the constructor is same as the object being created but why can't same be done with dynamic creation. Can someone provide a description with possible solution for this?
In Me a(&a); it takes an address of uninitialised variable a. The address is valid, but the object at that address doesn't exists yet. The object is considered existing once the constructor function is entered.
In Me* ak = new Me(ak); ak is not initialized unit after Me constructor returns. That results in passing an indeterminate value of ak into Me constructor.
Can someone provide a description with possible solution for this?
The solution for that is this:
struct Me {
Me() { std::cout << "Processing " << this << std::endl; }
};
See this pointer for full details.
This one the question from my assignment i can't understand what it's mean can anyone help me out with this please?
Write a class that contains two class data members numBorn and numliving. The value of numBorn should be equal to the number of object of the class that have been instanced. The value of numLiving should be equal to the total number of objects in existence currently(i.e the object that have been constructed but not yet destructed.)
You'll need to make your variables static data members of your class. Then your constructor(s) and destructor will increment and decrement as needed.
class A
{
public:
static std::size_t numBorn;
static std::size_t numLiving;
A()
{
++numBorn;
++numLiving;
}
~A()
{
--numLiving;
}
};
std::size_t A::numBorn = 0;
std::size_t A::numLiving = 0;
As a small demo
int main()
{
A a1;
A a2;
{
A a3;
std::cout << "living: " << A::numLiving << " born: " << A::numBorn << '\n';
}
std::cout << "living: " << A::numLiving << " born: " << A::numBorn << '\n';
}
will output
living: 3 born: 3
living: 2 born: 3
Note that when a3 falls out of scope, the numLiving is decremented from its destructor.
I encountered this issue, but I'm not sure what to make of it...
class Goo
{
char _ch;
string _str;
public:
function<void(void)> dobedo;
// Constructor 1
Goo(string s) : _str(s)
{
cout << "Constructed: [" << &_str << "]: " << _str << endl;
dobedo = [&]()
{
cout << "Dobedo: [" << &_str << "]: "<< _str << endl;
};
}
// Constructor 2
Goo(char ch) : _ch(ch)
{
dobedo = [&]() {
cout << "Dobedo: " << _ch << endl;
};
}
void show() { cout << "Show: [" << &_str << "]: " << _str << endl; }
};
int main()
{
string myStr1("ABCD");
string myStr2("EFGH");
vector<Goo> goos;
goos.push_back(Goo(myStr1));
goos.push_back(Goo(myStr2));
goos[0].dobedo();
goos[1].dobedo();
goos[0].show();
goos[1].show();
return 0;
}
For some reason, the function object wasn't able to print _str, despite being able to locate the memory address:
Constructed: [00EFF80C]: ABCD
Constructed: [00EFF7B0]: EFGH
Dobedo: [00EFF80C]:
Dobedo: [00EFF7B0]:
Show: [032F2924]: ABCD
Show: [032F296C]: EFGH
I did not have any problems with char variables though.
int main()
{
vector<Goo> goos;
goos.push_back(Goo('#'));
goos.push_back(Goo('%'));
goos[0].dobedo();
goos[1].dobedo();
return 0;
}
The output gives:
Dobedo: #
Dobedo: %
Any ideas?
You have undefined behaviour in your code without defining copy constructor. Default copy constructor copies all members by value. So your lambda object is copied and it holds references to destroyed object - _str (when vector had to be reallocated while calling push_back method).
Define copy constructor and move constructor for Goo class:
Goo(const Goo& g)
{
_str = g._str;
dobedo = [&]()
{
cout << "Dobedo: [" << &_str << "]: "<< _str << endl;
};
}
Goo(Goo&& g)
{
_str = move(g._str);
dobedo = [&]()
{
cout << "Dobedo: [" << &_str << "]: "<< _str << endl;
};
}
Your output clearly shows that the address of _str in constructor isn't the same as one in show. It means that your object was copied/moved. It may happen while it is pushed to a vector. BTW, it also may take place when you push/pop other elements to/from a vector as vector doesn't guarantee elements to stay at the same memory address.
When you create dobedo functor, all captured fields are copied to it. In the first case it was the address of _str which becomes invalid when the object is copied/moved (nobody updates it upon a move/copy!). Occasionally we may find an empty-string like stuff at that address (although accessing it is now a memory violation). In the second case, a character is captured and stored - and it definitely remains valid upon any object location change.
I was curios if default destructor is called, when I'm removing an element from an std::map. Here is an example which I have made:
class CTestMap{
public:
CTestMap() {
std::cout << "default constructor called" << std::endl;
}
CTestMap(int id) {
std::cout << "created object: " << id << std::endl;
m_id = id;
}
~CTestMap() {
std::cout << "destroyed object: " << this->m_id << std::endl;
}
int get_id(){
return m_id;
}
int m_id;
};
int main(void){
std::map<int, CTestMap>m;
std::map<int, CTestMap>::iterator m_it;
std::cout << "created map " << std::endl;
CTestMap t1(1);
std::cout << "created test object: " << t1.get_id() << std::endl;
CTestMap t2(2);
std::cout << "created test object: " << t2.get_id() << std::endl;
CTestMap t3(3);
std::cout << "created test object: " << t3.get_id() << std::endl;
m[1] = t1;
m_it = m.find(1);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m[2] = t2;
m_it = m.find(2);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m[3] = t3;
m_it = m.find(3);
std::cout << "inserted test object: " << m_it->second.get_id() << std::endl;
m_it = m.find(1);
std::cout << "will now erased test object: " << m_it->second.get_id() << std::endl;
m.erase(m.find(1));
std::cout << "erased test object: " << m[1].get_id() << std::endl;
m_it = m.find(1);
std::cout << "object shall no longer exist: " << m_it->second.get_id() << std::endl;
while(1);
return 0;
}
An here is the output:
./htest
created map
created object: 1
created test object: 1
created object: 2
created test object: 2
created object: 3
created test object: 3
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 1
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 2
default constructor called
destroyed object: 9377935
destroyed object: 9377935
inserted test object: 3
will now erased test object: 1
destroyed object: 1
default constructor called
destroyed object: 158830600
destroyed object: 158830600
erased test object: 158830600
object shall no longer exist: 158830600
Questions are:
Why so many times default constructor is called, when I'm only
creating 3 objects using my own constructor ?
Can I, based on
this example say, that each time I'm erasing any object from the
std::map, its destructor is called ? Is this general behavior of a
std::map ? I could not find this information.
What if I'm storing pointers to objects (I'm creating them using 'new' operator) ? When then delete shall be called ?
std::map stores a copy of the object you insert. When the
object is removed, it is this copy which is destructed. So
after m[1] = t1;, there are two identical instances of
CTestMap: t1 and the one in the map.
Also: m[1] = t1; will first create a new entry in the map,
using the default constructor, and later assign t1 to it.
In general, if you want to trace instance lifetime like this,
you need provide a user defined copy constructor and assignment
operator which trace as well. And you probably want to output
the this pointer in all of the traces. (Another technique
would be to dote each object with an immutable unique
identifier:
#define TRACE(m) std::cout << #m << '(' << m_objectId << ')' << std::endl
static int currentObjectId = 0;
class TestMap
{
int m_id;
int const m_objectId;
public:
TestMap()
: m_id( 0 )
, m_objectId( ++ currentObjectId )
{
TRACE(DFLT);
}
TestMap( int id )
: m_id( id )
, m_objectId( ++ currentObjectId )
{
TRACE(CTOR);
}
TestMap( TestMap const& other )
: m_id( other.m_id )
, m_objectId( ++ currentObjectId )
{
TRACE(COPY);
}
~TestMap()
{
TRACE(DTOR);
}
TestMap& operator=( TestMap const& other )
{
m_id = other.m_id;
TRACE(ASGN);
return *this;
}
};
You might want to add additional information (like m_id) to
the trace as well.
Also: your last output invokes undefined behavior. After
m.find(i), you should check first that the iterator hasn't
returned m.end(). If it has, dereferencing isn't allowed. So
your test output should be something like:
void
testOutput( std::map<int, TestMap> const& m, int i )
{
std::map<int, TestMap>::const_iterator entry = m.find( i );
if ( entry == m.end() ) {
std::cout << "no object at " << i << std::endl;
} else {
std::out << "object " << entry->second.m_id << " at " << i << std::endl;
}
}
(Finally: I think Microsoft has preempted the C prefix for
classes, so you should avoid it. If you want a prefix, choose
something else, to avoid confusion.)
If you store an actual object (rather than a reference or pointer), yes, the object gets destroyed when you erase it.
If you store pointers or references, then the object is not destroyed, and delete is not called on a pointer. If you want that to happen automatically, you should use a smart pointer (e.g. unique_ptr or shared_ptr depending on what behaviour you want).
If you don't use smart pointers, then you will need to take pointer stored, and delete the object yourself (after using erase to remove the element from the map).
Your default constructor is called a fourth time, because m[1] in
std::cout << "erased test object: " << m[1].get_id() << std::endl;
will construct a new object with key "1". This is because such an element doesn't exist in the map yet – otherwise it would just return that already existing object. (It did exist before, but you erased it in the line above! ;])
I have set up this example:
class UsefulClass {
public:
int id;
const bool operator< (const UsefulClass &other) const {
return this->id > other.id;
}
UsefulClass(int _id): id(_id) {
std::cout << "constructing " << id << std::endl;
}
~UsefulClass() {
std::cout << "destructing " << id << std::endl;
}
};
std::set<UsefulClass> set;
void create() {
UsefulClass object_1(1);
UsefulClass object_2(2);
set.insert(object_1);
set.insert(std::move(object_2));
std::cout << "create end" << std::endl;
}
int main() {
create();
std::cout << "main end" << std::endl;
}
I am expecting that the objects get destructed once when set gets deleted at the end of the program. But the objects get deleted twice:
constructing 1
constructing 2
create end
destructing 2
destructing 1
main end
destructing 1
destructing 2
Why is set.insert creating a copy here?
The objects in the set are different from the objects local to create(). The ones in the set are constructed using a copy constructor and move constructor, not the constructor UsefulClass(int), so you don't see their construction. The local objects get destroyed when the function create() returns, and then the objects in the set get destroyed at global cleanup after main ends.
object_1 and object_2 are created on stack and will be destroyed once the create() function ends. They need to be copied in the memory managed by set's allocator.
If you redefine the copy constructor, to trace its execution, you'll notice it is called at both inserts.
Rule of 3 applies to your case, if you print from dtor and want meaningful trace you should instrument copy (and maybe move) ctor also.
If you do that output will make sense and things should be properly paired.
Because your objects get copied on insertion into the set. Hence, when the create() function returns, the two local objects are destroyed. After main ends, the two copies that are in the set are destroyed, leading to the second pair of messages.
To illustrate whatever everybody has said before me, just create this simple example (it uses a new copy constructor for the set to use and uses a global variable to generate different ids each time a constructor is executed ---it's been tested, so you can put it in a file and compile):
#include <iostream>
#include <string>
#include <set>
using namespace std;
class UsefulClass {
static int instance;
public:
int id;
int i;
const bool operator<(const UsefulClass &other) const {
return id < other.id;
}
UsefulClass(int i){
id = instance++;
this->i = i;
cout << "constructing "
<< id
<< ":"
<< this->i
<< endl;
}
UsefulClass(const UsefulClass& other) {
id = instance++;
i = other.i;
cout << "constructing "
<< id
<< ":"
<< i
<< endl;
}
~UsefulClass(){
cout << "destructing "
<< id
<< ":"
<< i
<< endl;
}
};
int UsefulClass::instance = 0;
std::set<UsefulClass> myset;
void create() {
UsefulClass object_1(1);
UsefulClass object_2(2);
myset.insert(object_1);
/* please, explain what you mean with std::move, or which move
* have you used for the next statement. All i have is
* std::move(... ) for strings, but you have not defined
* string UsefulClass::operator string();
*/
myset.insert(/*std::move*/(object_2));
cout << "create end"
<< endl;
}
int main() {
create();
cout << "main end"
<< std::endl;
}
so you'll get a different instance id whenever you create a UsefulClass object and you'll see that when inserting into the set they are being copied as new instances. You'll see when each object is being created and when they are being deleted.
$ pru
constructing 0:1
constructing 1:2
constructing 2:1
constructing 3:2
create end
destructing 1:2
destructing 0:1
main end
destructing 2:1
destructing 3:2