C++Guns – RoboBlog

13.01.2019

C++ Guns: -Wshadow for constructor arguments

Filed under: Allgemein — Tags: — Thomas @ 14:01

-Wshadow is not that bad. We live in a modern world and don't use C if we can use C++ with a better defined scope and namespaces. So we can catch more errors on compile time.

First: what kind or errors can be detected with -Werror=shadow

Warn whenever a local variable or type declaration shadows another variable, parameter, type, class member, or whenever a built-in function is shadowed.

struct A {
    int i;              // note: shadowed declaration is here

    void func(int i) {} // error: declaration of 'i' shadows a member of 'A' [-Werror=shadow]
};

This kind or error also occurs if you define a constructor like following code. It defines a type Axis which has a title and a range. The range must be valid. The constructor of the Axis does something. So aggregate initialization is not possible.

struct Axis {
    string title;
    Range range;

    Axis(string title, Range range) 
    : title(title), range(range)       // error: declaration of 'range' shadows a member of 'Axis'
                                       // error: declaration of 'title' shadows a member of 'Axis'
    {
        // check if range is valid, error otherwise
    }
};

You can, of course, rename the constructor arguments or member variables. But that is not nice and results in either ugly code or a less proper interface.

The right solution is to split your type into two. One which only store data and another which does something with that data. Let's call the data-type AxisData. Try again:

struct Axis {
    struct AxisData {
        string title;
        Range range;
    };

    AxisData d;

    Axis(string title, Range range) 
    : d{title, range}
    {
        // check if range.isValid()
    }
};

No more errors! The extra variable d is no overhead, as you can see in my previous post.
To hide this implementation details from the programmer, provide some access function and switch from struct to class because Axis is now a type which manage it's data.

So this is the (final, add some references) implementation:

class Axis {
    struct AxisData {
        string title;
        Range range;
    };

    AxisData d;

public:

    Axis(string title, Range range) 
    : d{title, range}
    {
        // check if range.isValid()
    }

    string title() const {
        return d.title;
    }

    Range range() const {
        return d.range;
    }
};

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress