lis-epfl/MAVRIC_Library

Assignment operator with references

Closed this issue · 4 comments

Has anyone ever experienced any issues with this? Or know how to get around it?

If you have references in a class and need to use an assignment operator with it, you will get compiler errors. For example:

class MyClass
{
public:
    MyClass(int& foo);
private:
    int& foo_;
};

Then, if you try to do this,...

int bar = 0;
MyClass x = MyClass(bar);

... it will not compile because a temporary object is created first and then assigned to the variable x. If you try to create an overloaded assignment operator function in MyClass, it won't compile because you can't assign to a reference variable after it has been declared.

You can do something like this,...

MyClass x(bar);

...but it only works on declarations.

For most of our modules, we create it once in an initialization list and then have no need to make more. But I've written a Waypoint class that will be created or destroyed when MAVLink messages tell it to do so.

A possible way to get around this is to use pointers instead of references. It would first create an object with undefined pointers and then assign the pointers during the assignment operator function. But that brings back the issues of having to ensure that the pointer is actually pointing to what we believe it is pointing to and trusting that no one has changed it... and if it is not, then the drone will crash. It would also be weird if we weren't consistent with our references vs. pointers convention.

You cannot have uninitialized references. You can copy objects like this using the auto-generated copy constructor:

#include <iostream>

class MyClass
{
public:
    MyClass(int& foo):
        foo_(foo)
    {;}

    void print(void)
    {
        std::cout << foo_ << std::endl;
    }

private:
    int& foo_;
};

int main(void)
{
    int bar = 42;

    MyClass x(bar);
    MyClass y(x);     // Copy x into y

    x.print();
    y.print();

    bar = 0;

    x.print();
    y.print();

    return 0;
}

But as you said it only works at object creation, you cannot first create an array of objects, then copy another object into one element of the array...

I do not think there is a way around this limitation. Except maybe removing the reference... what do you need to refer to?

I am having the waypoint class have Mavlink_stream so it can send itself as a MAVLink message to the ground control station and Position_estimation so I can do conversions between the various reference frame. I have it working at the moment with pointers instead, but not references.

I was also splitting the Mavlink_waypoint_handler class into various smaller classes but there were too many circular references between each other, which cannot be done with references as well since one must assign the other before it is created. I'm planning on getting around that by just completely redesigning the code so there wouldn't need to be any.

Ok! that sounds great!

  • memory allocation. Until now we avoided dynamic allocation at runtime. We preferred to allocate things statically, or during initialization. Please avoid dynamic memory allocation if you want to add/remove a waypoint.
  • mavlink_stream. You could have a proxy object which role is to convert a waypoint object into a mavlink message. Very similar to the *_telemetry modules.
  • frame conversion. In #278 , local_position_t no longer has an origin field. We have the origin which is a static member of the class INS (an interface for position estimation). This is done so that all instances of INS share the same origin. But I am open to other solutions that would be more convenient for the waypoints, like a static origin somewhere, along with static methods for frame conversion. That would remove the need of a reference to INS.

That's a good idea.

And the origin being a static member of the INS class is perfect because then I don't need to even give some objects Position_estimation for the origin. I can just call INS::origin().