user2946316
user2946316

Reputation:

c++ - Pointers and addresses

I'm just playing around a little bit with reflection and I'm seeing something that doesn't make sense to me. The application pretty much asks you to type in the name of a class and if it founds it in the map, it creates a instance of that class and prints out the address of the object.

The first time i type in Derived1, It generates 1 address for example (0x00001), the second time i type in the same name it shows another address (0x00002) and the third time it keeps using the same address again.

How come i only get a new address for the second object and not for the rest of the objects?

This is by no means a problem, I'm just curious.

#include <iostream>
#include <memory>
#include <map>
#include <string>
#include <vector>
#include <typeinfo>

class Base
{
protected:
    int id;
public:
    Base(int _id)
        :id(_id)
    {
        std::cout << "Im the base class, and this is my address: " << this << std::endl;
    }
    virtual void PrintMyAddress() const = 0;
    void PrintId()
    {
        std::cout << "This is my ID: " << this->id << std::endl;
    }
    virtual ~Base(){}
};

class Derived1 : public Base
{
public:
    Derived1(int _id) : Base(_id){}
    void PrintMyAddress() const override
    {
        std::cout << "I'm derived 1, this is my address: " << this << std::endl;
    }
    ~Derived1(){}
};

class Derived2 : public Base
{
public:
    Derived2(int _id) : Base(_id){}
    virtual void PrintMyAddress() const override
    {
        std::cout << "I'm derived 2, this is my address: " << this << std::endl;
    }

    virtual ~Derived2(){}
};

class Derived3 : public Derived2
{
public:
    Derived3(int _id) : Derived2(_id){}
    void PrintMyAddress() const override
    {
        std::cout << "I'm derived 3, this is my address: " << this << std::endl;
    }

    ~Derived3(){}
};

class Generate
{
private:
    typedef std::unique_ptr<Base> (Generate::*SomeFunction)(int);
    std::map<std::string, SomeFunction> listFunction;

public:
    Generate()
    {
        this->MapClasses();
    }

    template <typename T>
    std::unique_ptr<Base> CreateDerived(int _id)
    {
        std::unique_ptr<Base> tmp(new T(_id));
        return std::move(tmp);
    }

    void MapClasses()
    {
        this->listFunction["Derived1"] = &Generate::CreateDerived<Derived1>;
        this->listFunction["Derived2"] = &Generate::CreateDerived<Derived2>;
        this->listFunction["Derived3"] = &Generate::CreateDerived<Derived3>;
    }

    std::unique_ptr<Base> Class(std::string _name)
    {
        if (this->listFunction.find(_name) != this->listFunction.end())
        {
            return std::move((this->*this->listFunction[_name])(rand() % 100));
        }
        else
        {
            std::unique_ptr<Base> itsnull;
            return std::move(itsnull);
        }
    }

    std::map<std::string, SomeFunction>& GetFunctionList()
    {
        return this->listFunction;
    }
};


int main()
{
    Generate gen;
    bool run = true;
    while (run)
    {
        std::cout << std::endl << "What class do you want to generate? Type in the name of the class: " << std::endl << std::endl;
        std::string className;
        std::cin >> className;
        if (className == "exit")
        {
            run = false;
            continue;
        }

        auto genclass = gen.Class(className);
        if (genclass.get())
        {
            genclass->PrintMyAddress();
            genclass->PrintId();
            std::cout << "This is my TypeID: " << typeid(*genclass).name() << std::endl;
        }
        else
        {
            std::cout << "Class couldn't be created because it doesn't exist..." << std::endl;
        }
    }

    std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
    return 0;
}

This is a similar example but always shows the same address:

for (int i = 0; i < 10; ++i)
{
    int* test = new int;
    std::cout << test << std::endl;
    delete test;
}

Is the compiler optimizing everything after the second creation?

Upvotes: 0

Views: 98

Answers (2)

Quicky
Quicky

Reputation: 411

When I test you code on Linux with gcc 4.9.0 and ask for Derived1 3 times I always obtain the same address (0xdead by example) The reason is that compiler replace line

auto genclass = gen.Class(className);

by

std::unique_ptr<Base> genclass = gen.Class(className);

When the execution reach the end of the wile loop local variable genclass is destroyed
the unique_ptr do its job by deleting the object it points which make the address 0xdead available for use
Next iteration will create a new object and reuse 0xdead addresse because it is available
In your case the memory allocation mechanism behind is perhaps slightly different and address is seen available only at third iteration

You can check the destruction of your object performed by unique_ptr by putting a breakpoint on Base destructor or adding an instruction like the following in the destructor :

std::cout << "Delete base whose address is " << this << std::endl;

Upvotes: 0

Mike Vine
Mike Vine

Reputation: 9837

Your code basically created a new object then deletes it each loop.

The address of the object is dependent on where the heap puts it. The heap is free to reuse space that's been recently free'd up (and it would be silly if it didn't) and so you are very likely to get repeat address's.

Upvotes: 1

Related Questions