c++ how to create my own warning in compilation time - c++

I want to create my own warning in compilation time and not in pre-processor (as I've seen a few answers to)
Let's say we have:
class A
{
private:
explicit A(A const& other);
};
now if the user does:
A first;
and then:
A second(first);
he'll get an error that copy constructed is not implemented or whatever.. bare in mind that my code has a lot of inheritances in it... as well as referring me to the H file A is implemented in and not where I tried to use copy constructor...
so.. instead of the compiler's default warning I'd like to create my own....
something like.. "You cannot use copy constructor"
Help?
Thanks!

Using a static_assert with a user-define message will trigger this error message during compilation
class A
{
private:
A() {}
explicit A(A const& /* other */)
{
static_assert(false, "You cannot use copy constructor");
}
};
int main()
{
A first;
A second(first); // compile error
}
Output on LiveWorkSpace
Note this will produce an error and not a warning. However, it is almost always best to use a "warnings as errors" compiler option and to explicity (i.e. documented with a comment) disable warnings that you know are innocuous.

Without preprocessor, using only standard C++, it's unreal. You can use static_assert, but it's not warning.

Related

Detect use after move during compilation?

The clang-tidy static analyzer detects uses of variables after being moved.
class a_class {
std::unique_ptr<int> p_;
public:
auto p() -> auto& {return p_;}
void f() const {}
};
int main() {
auto aa = a_class{};
[[maybe_unused]] auto bb = std::move(aa);
aa.f();
}
error: Method called on moved-from object 'aa' [clang-analyzer-cplusplus.Move,-warnings-as-errors]
This great! ©.
How can I make the compiler, clang or GCC detect the same issue too? Either by activating some warning option or by some (non-standard?) attribute?
I tried using -Wmove in clang and the [[consumed]] attribute but they didn't help.
Perhaps I used them incorrectly.
The code is here: https://godbolt.org/z/18hr4vn7x (the lower panel is clang-tidy and the mid panel on the right is the [empty] compiler output)
Is there a chance a compiler will warn about this or it is just too costly for the compiler to check for this pattern?
I found one way to do it, using attributes in clang. .
(A GCC or a more standard solution is still welcome.)
needs clang 6 or higher
mark the class as "consumable"
mark the method(s) "callable-when-unconsumed" (not sure how to make this the default)
class [[clang::consumable(unconsumed)]] a_class {
std::unique_ptr<int> p_;
public:
[[clang::callable_when(unconsumed)]]
void f() {}
// private: [[clang::set_typestate(consumed)]] void invalidate() {} // not needed but good to know
};
https://godbolt.org/z/45q8vzdnc
The recipe is simplified from https://awesomekling.github.io/Catching-use-after-move-bugs-with-Clang-consumed-annotations/ .
I couldn't find detailed documentation on how to use the these features.
It is simplified because:
a) it seems that "clang-consumable" moved object becomes "consumed" by default when moved-from, so it is not necessary to write a special function to invalidate if not necessary (no need for [[clang::set_typestate(consumed)]]).
b) constructors seem to leave the object in an unconsumed state by default (no need for [[clang::return_typestate(unconsumed)]]);
If a compiler isn't built with a setting to do this, then you can't make it do this. Use-after-move is a legitimate thing in C++, so no compiler is obligated to consider it an error.
These kinds of things are what static analyzers are for.

Handling "Thrown exception type is not nothrow copy constructible" Warning

Going back to C++ development after a 12 years hiatus. I'm using JetBrains's CLion software which is great since it provides a lot of input on possible issues on my class design. One of the warning I get in my class' constructor throw statement is: Thrown exception type is not nothrow copy constructible. Here is a code sample that generates this warning:
#include <exception>
#include <iostream>
using std::invalid_argument;
using std::string;
class MyClass {
public:
explicit MyClass(string value) throw (invalid_argument);
private:
string value;
};
MyClass::MyClass(string value) throw (invalid_argument) {
if (value.length() == 0) {
throw invalid_argument("YOLO!"); // Warning is here.
}
this->value = value;
}
This piece of code compiles and I am able to unit test it. But I would like very much to get rid of this warning (in order to understand what I am doing wrong, even though it compiles).
The comment provided by Neil is valid. In C++ 11, using throw in a function signature has been deprecated in favor of noexcept. In this case, my constructor's signature should have been:
explicit MyClass(string value) noexcept(false);
But, since noexcept(false) is applied by default to all functions, unless noexcept or noexcept(true) is specified, I can simply use:
explicit MyClass(string value);
Going back to how to fix the "Thrown exception type is not nothrow copy constructible” warning, I found this post that explains very well what the issue is and how to fix it.

Calling constructor using this->classname::classname(...)

I would like to know where is this form of constructor calling is documented.
This syntax apparently works since Visual Studio version 6.0 (I know it does not compile using G++).
Please note that I am not looking for alternatives and I don't need to know that it's good or evil.
class Foo
{
public:
int m_value;
Foo() : m_value(0) {}
};
Foo o;
o.m_value = 5;
o.Foo::Foo(); // Explicit constructor call!
EXPECT_EQ(0, o.m_value); // True!
I first found this syntax reading this article:
http://www.dreamincode.net/forums/topic/160032-finite-state-machines/
This post also refers to this syntax as well:
Can I call a constructor from another constructor (do constructor chaining) in C++?
Another post discussing the matter:
Explicit constructor call in C++
The supposed explicit constructor call is not valid C++ syntax. The fact that MSVC accepts such code is a bug.
Its of no use since you are creating a transient object in between and it dies when the scope ends.What ever value contain in object o remains the same, so u got the True value

Why does this functor ("lambda") give a weird warning?

When I compile and run this with Visual C++ 2010:
#include <iostream>
int main() {
int subtrahend = 5;
struct Subtractor {
int &subtrahend;
int operator()(int minuend) { return minuend - subtrahend; }
} subtractor5 = { subtrahend };
std::cout << subtractor5(47);
}
I get the correct answer, 42.
Nevertheless, the compiler complains that this is impossible:
Temp.cpp(9) : warning C4510: main::Subtractor : default constructor could not be generated
Temp.cpp(6) : see declaration of main::Subtractor
Temp.cpp(9) : warning C4512: main::Subtractor : assignment operator could not be generated
Temp.cpp(6) : see declaration of main::Subtractor
Temp.cpp(9) : warning C4610: struct main::Subtractor can never be instantiated - user defined constructor required
What's going on?
The first two warnings are just letting you know that the implicitly declared member functions cannot be generated due to the presence of a reference data member.
The third warning is a Visual C++ compiler bug.
All three warnings can be ignored with no ill effects, though you can easily make all three go away by making the reference data member a pointer instead (reference data members are almost never worth the trouble).
The first warning is to tell you that a reference value cannot be defaultly constructed(references are guaranteed to point to some value). Switch the subtrahend to a regular integer and the problem will go away.
I am pretty sure the second warning is of similar nature.
(Just saying, it is generally much better to rely on something like boost::function or a similar implementation(std::tr1::function?) instead of writing this code manually)
It's because the variable subtractor5 is an unnamed struct. If you want to make the errors go away, give the structure used for subtractor5 a name.
For example:
struct subtractor {
:
} subtractor5 = { subtrahend };
I unfortunately don't know enough C++ language-ese to know why it works, but I do know why the warning happens.
A user defined constructor is mandatory in following cases:
Initializing constant data members (const int c_member;).
Initializing reference data members (int & r_member;)
Having a data member whose type doesn't have default constructor. Eg:
class NoDefCtor
{
public:
NoDefCtor(int);
};
class ContainThat
{
NoDefCtor no_ctor_member;
};
Inheriting from a base class, where base class doesn't have default constructor. Almost same as above (NoDefCtor).

Find uninitialized variables in C&C++

I really mean C and C++. This project is using a lib in C which is calling my functions in C++. However the functions are in extern "C" because the lib expects it.
Anyways, in these functions I do new Blah. When a specific function is called (end_tree) i expect all my variables to be initialized. Using Visual Studios, GCC or any other compiler is there a way i can check? I just notice some bools are TRUE which shouldn't be... why, because it wasn't initialized. Is there some kind of _VS_CheckThisMemory(mytree) function or magic I can use?
Don't know it this is what you want but gcc has -Wmaybe-uninitialized and -Wuninitialized. There may be more on the warning options page.
Use valgrind (on linux)
./valgrind myprogram
Especially easy when myprogram was compiled with debug info (gcc -g), but not required. Valgrind will notify where memory is being used that was uninitialzed, and where it was allocated from. If it has debug info, valgrind will report exactly at which file:linenumber things happened. (it can even attach a debugger on the fly for you to insepct things)
It will also detect access beyond allocation boundaries and access after freeing. This is incredibly useful.
Here endeth the useful answer
Edit because it wasn't exactly clear why I was posting the following, as became clear from the comment, let me introduce the remainder of this answer:
When starting to use valgrind with existing codebases, it is almost inevitable that you'll get 'false' positives, i.e. reports that aren't really problems (yet). I include one example of what might trigger such a report, and how you'd typically fix those.
I'm just including this to raise awareness of how to tackle or recognize (semi-)false positives.
Another way of wording it (with reference to Matthieu's convincing reasoning in the comments) is to treat even the 'not-actually-killing' Valgrind warnings as critical: get them fixed, not forgotten.
It is possible that valgrind will report uninitialized access when it is not really a problem. Like, e.g.
char buf[1024];
strcpy(buf, "hello");
char clone[1024];
memcpy(clone, buf, 1024);
You should fix that by doing something smarter like
memcpy(clone, buf, strlen(buf));
To make sure there are no uninitialzed 'parts' in buf (or at least not in the area accessed)
Use a self-initializing class to cover those annoying primitives.
template<typename T> class always_initialized {
T t;
public:
always_initialized()
: t(T()) {}
always_initialized(const T& ref) {
: t(ref) {}
operator T&() { return t; }
operator const T&() const { return t; }
T& operator=(const T& ref) { return t = ref; }
};
In response to the code linked in the comment, RAIIIA (Resource Acquisition is Initialization In Action (R))
class OtherClass;
class MyClass : public SomeBase {
public:
// note I got rid of your default constructor, which leaves values unitialized
MyClass(Var* name, OtherClass* loop)
: m_name(name), m_loop(loop) // this right here
{ }
virtual ~MyClass(); // no implementation needed here
void save();
// made the members protected, other classes have no business accessing them directly
protected:
Var* m_name;
OtherClass* m_loop;
};
Your default constructor left the values unitialized, and goes against RAII in its pure form. It's OK to do that, but as you're having problems with uninitialized variables, I would recomment removing default constructors.
EDIT: storing unknown pointers as class members without newing and deleteing them in the class constructor/destructor isn't really RAII, but I hope you do that somewhere.
I solved this by using a solution with templates to act like properties. I used Property like features in C++? but there are other examples for other things like passing in a get/setter.
Essentially generated most of this code bc i was able to and i kept track if a variable was set or not through the property. At the end i just check members and had asserts to tell me if i set a variable or not. I also assert when i 'get' just in case.