Understanding -Weffc++

Understanding -Weffc++

GCC's -Weffc++ has several issues, I never use it. The code that checks for "problems" is pretty simplistic and so the warnings end up being far too blunt and unhelpful.

That particular warning is based on Item 11 of the first edition of Effective C++ and Scott changed it (for the better) in later editions. The G++ code doesn't check for actual dynamic allocation, just the presence of pointer members.

See what I wrote about this warning in GCC's bugzilla when comparing the guidelines in the first edition with the third edition:

Item 11: Define a copy constructor and an assignment operator for classes with
dynamically allocated memory.


Replaced by Item 14: "Think carefully about copying behavior in
resource-managing classes" - the advice is less specific, but more useful. I'm
not sure how to turn it into a warning though!

Weffc++ warning on simple structure with shared_ptr

With the Effective C++ warning enabled, the compiler is warning that you haven't followed the guideline to prefer explicit initialisation of the member fields in the initialiser list.

Adding an explicit constructor will probably get rid of this:

node() : left(), right(), value()
{}

returning *this gives Weffc++ warning

Change your code to:

class test : public base
{
public:
test& operator=(int)
{
return *this;
}
};

And everybody will be happy, not just your compiler.

PS: If you wish to know more the warnings produced by -Weffc++ are an extract of the recommendations found in this book :

Effective C++: 55 Specific Ways to Improve Your Programs and Designs,
Addison–Wesley, 1992, (ISBN 0-321-33487-6).

C++ -Weffc++ warning with pointers

With B the compiler can detect that the Rule of Three is potentially being violated and raises the Effective C warning. Resolving this is covered well in many other places starting with Ted Lyngmo's answer to this question.

But why don't the other two trigger the same warning?

C allows us to eliminate half of the concern: The reference member variable cannot be re-assigned preventing the compiler from generating a default assignment operator to cause any grief.

C c; // uninitialized second. GCC misses this
C d;
c = d; //fails. deleted assignment operator

but the copy constructor should still be possible and a potential threat.

C c; // uninitialized second. GCC misses this
C d(c); // but it does catch the uninitialized second if you do this

Making a modification to C

std::vector<int> dummy;
struct C
{
C() :second(dummy) // initialize second
{

}
int * first = nullptr;
std::vector<int>& second;
};

Allows

C c; 
C d(c);

to compile without the Effective C++ warning just like A. I couldn't wrap my head around this for a long while. This brings up an important point. Warnings are given by the grace of the Implementor. If something is hard or impossible to prove, there will be no warning.

But why is this warning hard?

The compiler has to know to look for a potential problem. This means it will be looking for the signature of the problem. This means one or more members that may require special handling, a destructor, copy constructor, or assignment operator without at least one of the other two special member functions required by the Rule of Three.

I suspect GCC is triggering the Effective C++ warning when it finds a at least one of the special member functions but not all.

Let's look at the destructors of the three classes.
A's int requires no special destruction logic. Neither does a C's reference. B's vector is a different story. At the very least it needs to release some storage. This requires the compiler to generate some code, and once there's a more than a do-nothing destructor the compiler can see that the class has a destructor without the other two parts of the Rule of Three and contains members that may require special handling (the pointer).

So

struct C
{
C() :second(dummy)
{

}
~C() // force a destructor
{

}
int * first = nullptr;
std::vector<int>& second;
};

Should, and does, raise the effective C++ warning.

Note: the utterly trivial copy constructor generated by

C c; 
C d(c);

doesn't seem to set off the warning by itself. Nor does providing a copy constructor. The warning's hook may be solely on the destructor, leading back to the caveat about warnings existing only by the grace of the Implementor.

Overriding +/-/*/% by integer and the -Weffc++ flag

Just to elaborate on Grizzly's comment... This is not the in-place multiplication. As such, you should declare it const to explicitly prevent that:

Coord Coord::operator*(int n) const {
Coord c(*this);
c.x *= n;
c.y *= n;
return c;
}

Or if you have a useful constructor:

Coord Coord::operator*(int n) const {
return Coord(x*n, y*n);
}

The in-place multiplication is different (and non-const):

Coord& Coord::operator*=(int n) {
x *= n;
y *= n;
return *this;
}

Is There a -Weffc++ Equivalent for MSVC (Visual C++)?

There's not any equivalent.

Visual C++ doesn't have warning groups at all, only the warning level slider, and the ability to disable individual warnings. So none of the GCC/clang warning group options have an equivalent.

Beyond that, the Effective C++ book is rather old and some of its advice is no longer considered to be best practices. So enforcement has minimal value.

Some editions of Visual C++ come with code analysis, which has many more of these checks than the basic compiler. That's turned on using /analyze, documentation is here: https://learn.microsoft.com/en-us/visualstudio/code-quality/code-analysis-for-c-cpp-overview



Related Topics



Leave a reply



Submit