指针和地址

Pointers and addresses

本文关键字:地址 指针      更新时间:2023-10-16

我只是在玩一点反射,我看到一些对我来说没有意义的东西。应用程序基本上要求您输入一个类的名称,如果在映射中找到它,它就创建该类的一个实例,并打印出对象的地址。

第一次i在Derived1中键入时,它生成一个地址例如(0x00001),第二次i在相同的名称中键入时,它显示另一个地址(0x00002),第三次它再次使用相同的地址。

为什么我只得到第二个对象的新地址,而不是其他对象的新地址?

这根本不是问题,我只是好奇。

#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;
}

这是一个类似的例子,但总是显示相同的地址:

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

编译器在第二次创建后优化一切吗?

你的代码基本上创建了一个新对象,然后在每个循环中删除它。

对象的地址取决于堆把它放在哪里。堆可以自由地重用最近释放的空间(如果不这样做就太愚蠢了),所以你很可能会得到重复的地址。

当我用gcc 4.9.0测试Linux上的代码并要求Derived1 3次时,我总是获得相同的地址(例如0xdead)原因是编译器替换了

auto genclass = gen.Class(className);

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

当执行到while循环结束时,局部变量genclass被销毁
unique_ptr通过删除它所指向的对象来完成它的工作,从而使地址0xdead可用
下一次迭代将创建一个新对象并重用0xdead地址,因为它是可用的
在您的情况下,内存分配机制可能略有不同,地址仅在第三次迭代时可用

您可以通过在基析构函数中添加断点或在析构函数中添加如下指令来检查unique_ptr执行的对象的析构:

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