【问题标题】:C++ - non-static void* member pointing to another non-static member of different objects having same address but distinct valueC ++ - 指向具有相同地址但不同值的不同对象的另一个非静态成员的非静态void *成员
【发布时间】:2020-05-18 07:23:09
【问题描述】:

这个问题标题不清楚,有点破。我尝试使用成员 void* 来存储另一个成员的地址。我无意中发现了一个奇怪的问题。在vector<T> 中创建了三个Object 对象。但是当我查看这三个val_addr 的值时,它们总是指向同一个地址,但显然每个val 总是唯一的。

class Object {

protected:
    int val {0};

    void *val_addr = nullptr;

    std::vector<Object> objs;

public:
    Object() = default;

    Object(int val) 
    {
        this->val = val;
        this->val_addr = (void *) &this->val;
        std::cout << "val_addr: " << val_addr << "\n"; // always 0X123456 for example
    }

    std::vector<Object>& get_objs() 
    {
        return objs;
    }

};

class Iterable : public Object {
public:
    Iterable(const std::set<int>& values) { // {1, 2, 3} inside values
        for (const auto & c : values) {
            this->objs.emplace_back(c);
        }
    };
};

【问题讨论】:

  • 想想当Object 被复制或移动时会发生什么
  • 您将参数 int val 的值复制到对象的字段 (int val {0}) 中,但您并未将其指向新位置。然后,当您更新值时,您会读取字段的地址(不会随着您使用的对象而改变)。
  • 另外,void* 演员表无效。 stackoverflow.com/questions/13875786/…
  • 您可能不会期望不同的地址,因为每次调用 emplace_back 时可能会重新分配。当您从新创建的对象中打印出地址时,旧对象已被移动,并且先前打印的地址已更改
  • @S.M.我的理解是每次调用emplace_back,就会有一个临时对象,以后会被盗。但即使我使用push_back,结果也一样。

标签: c++


【解决方案1】:

任何指向对象成员的指针在向量扩展后都会失效。在放置新的向量元素并扩展向量后,您在对象构造函数中看到的地址无效。所以你在创建对象的那一刻看到了地址,而当你查看另一个对象内部的成员的地址时,之前的地址是无效的,可能无法进行比较。复制了前面的对象并更改了&amp;this-&gt;val,但this-&gt;val_addr 仍然包含旧的无效地址。您应该在复制构造函数中更新this-&gt;val_addr

class Object {
protected:
    int val {0};
    int *val_addr = nullptr;

public:
    Object() = default;

    Object(int val) 
    {
        this->val = val;
        this->val_addr = &this->val;
        std::cout << "val_addr: " << val_addr << "\n";
    }

    Object(const Object& obj) 
    {
        this->val = obj->val;
        this->val_addr = &this->val;
        std::cout << "new val_addr: " << val_addr << "\n";
    }

    std::vector<Object> &get_objs() const 
    {
        return objs;
    }
};

【讨论】:

  • 我已经厌倦了resize() 以防止扩展,但结果相同。
  • 只需添加复制构造函数即可。您总是在堆栈上的临时对象中打印地址。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-02
  • 2015-09-18
  • 2014-11-04
  • 1970-01-01
  • 2010-11-02
  • 1970-01-01
  • 2013-08-25
相关资源
最近更新 更多