0

This question title is not clear and a bit broken. I tried to use a void* which is a member to store the address of another member. I accidentally found a weird problem. There were three Object objects created inside a vector<T>. But when I look at the value of those three val_addr, they always point to the same address, but apparently each val is always unique.

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);
        }
    };
};
user2672165
  • 2,986
  • 19
  • 27
SpellTheif
  • 715
  • 2
  • 12
  • 26
  • 4
    Think about what happens when an `Object` is copied or moved – Mat May 18 '20 at 07:27
  • You're copying the value of the parameter `int val` into your object's field (`int val {0}`), but you're not pointing it to a new location. Then when you've updated the value, you read the address of the field (which will not change with the object you're using). – Rogue May 18 '20 at 07:27
  • Also that `void*` cast isn't valid. https://stackoverflow.com/questions/13875786/pointers-to-members-representations – Mat May 18 '20 at 07:28
  • You may not expect different addresses because of possible reallocations on each call `emplace_back`. When you print out the address from a newly created object, the old object has been moved and the previously printed address changed – 273K May 18 '20 at 07:29
  • @S.M. My understanding is each time I call `emplace_back`, then there is a temp object and it will be stolen later on. But even I use `push_back`, same result. – SpellTheif May 18 '20 at 07:39

1 Answers1

0

Any pointers pointing object members are invalidated after the vector extended. The address you see in the object constructor is not valid after a new vector element is placed and the vector is extended. So you saw the address at the moment of an object creation, and when you look at the address of a member inside another object, the previous address is not valid and may not be compared. The preceding object is copied and &this->val is changed, but this->val_addr still contains the old and invalid address. You should update this->val_addr in the copy constructor.

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;
    }
};
273K
  • 29,503
  • 10
  • 41
  • 64