c++address-operator

Address of Object within array returned by function


I am gradually porting and refactoring C code to C++.

In the original C code, I have constructs like this:

Object* obj = &objects[index];

where objects is a global Object[].

I refactored the code so the array is dynamically allocated and a different object holds the array:

struct Info {
    Object* objects;
};

Due to my gradual refactoring, I wrote the following free function:

Object* GetObjects(Info* i) {
    return i->objects;
}

Now my question is:

Does the following code behave like I would expect (getting the address of an object in the array)?:

Object* obj = &GetObjects(info)[index];

Am I getting the Address of an object in the array (what I want) here or the address of the pointer or some rvalue and invoke UB? [] has higher precedence than & but does that also count for function calls?


Solution

  • This line:

    Object* obj = &GetObjects(info)[index];
    

    Is valid, and should not cause UB by itself. GetObjects(info) returns a Object* (not an rvalue which you were worried about), then it is accessed with operator[].

    However - the code relies on the Object* array to stay alive as long as obj is used. If info is the owner of it, it will require info to stay alive as well (assuming it is responsible for its lifetime).

    Notes:

    1. Regardless of operator precedence, using paretheses will make is a bit clearer:
      Object* obj = &(GetObjects(info)[index]);
      
    2. Since you use C++, you can add the following method to struct info:
      struct info
      {
          Object * GetObjectAtIndex(int index)
          {
              // TODO: check that the index is valid and return nullptr if not
              return &(objects[index]); 
          }
      };
      
    3. Using references instead of pointers might help to avoid some bugs:
      struct info
      {
          Object & GetObjectAtIndex(int index)
          {
              // TODO: check that the index is valid, decide what to return if not
              return objects[index]; 
          }
      };
      
    4. It is recommended to use std::vector instead of raw C arrays. It also supports a dynamic size as you require. One caveat: std::vector might need to reallocate when enlarged, and when doing so iterators, references and pointers into it will be invalidated.