C26432 If you define or delete any default operation in the type 'type-name', define or delete them all (c.21) - mfc

I have declared a destructor like this in the CPP file:
CResizingDialog::~CResizingDialog()
= default;
And in the H file:
virtual ~CResizingDialog(); // Destructor
Yet, it is flagging code inspection issues:
I see the docs here. I am not sure what I should do here.

Related

Default C++ definitions in body or header files

Scott Meyer states in Effective C++: Item 30: Understand the ins and outs of inlining that constructors and destructors are often worse candidates for inlining.
Defining functions inside a class definition, requests (not commands) them implicitly to be inline. Depending on the quality of your compiler, the compiler decides whether or not (explicitly or implicitly) defined functions be actually inlined or not.
Taking all these into account, is it a better practice to explicitly define empty/copy/move constructors, copy/move assignment operators and destructors as default (i.e. with the default keyword) inside the body files than inside the header files? After all, default deals purely with implementation as opposed to the dual delete?
Without ever reading "Effective C++: Item 30" I can definitely tell that it makes perfect sense to define empty-looking ctors/dtors inside .cpp:
// MyClass.h:
class MyClass
{
public:
MyClass();
~MyClass();
...
}
// MyClass.cpp:
MyClass::MyClass() = default;
MyClass::~MyClass() = default;
This might look like waste for digital ink, but this is exactly how it has to be done for heavy classes that have large inheritance list or lots of non trivial members.
Why do I think it has to be done like this?
Because if you don't do that, then in every other translation unit where you create or delete MyClass compiler will have to emit inline code for entire class hierarchy to create/delete all members and/or base classes. In giant projects this is usually one of main reasons for builds that takes hours.
To illustrate, compare generated assembly with non-inline ctor/dtor and without. Not that if you have multi-level inheritance with virtual classes then amount of generated code grows very fast. Some call it C++ code bloat.
Basically if you have inline function in your class and you use that function in N different cpp files (or worse in some header files that are used by many other cpp files) then compiler would have to emit that code N times in N different object files, and then at link time merge all these N copies into one version. This rule applies basically to any other function, however, it's not very common to make large function inline in header files (because it's just bad). The issue with constructors, destructors and default assignment operators etc is that they may look like empty or no c++ code at all, while they actually need to perform that same operation recursively for all members and base classes and all of that results in very large amount of generated code.
Another use case of defining a destructor = default inside the body file, is the PImpl idiom in combination with std::unique_ptr.
header file: example.hpp
#include <memory>
// Example::Impl is an incomplete type.
class Example
{
public:
Example();
~Example();
private:
struct Impl;
std::unique_ptr< Impl > impl_ptr;
};
body file: example.cpp
#include "example.hpp"
struct Example::Impl
{
...
};
// Example::Impl is a complete type.
Example::Example()
: impl_ptr(std::make_unique< Impl >())
{}
Example::~Example() = default; // Raw pointer in std::unique_ptr< Impl > points to a complete type so static_assert in its default deleter will not fail.
At the point in the code where std::unique_ptr< Impl > is destroyed, Example::Impl must be a complete type. Therefore, implicitly or explicitly defining Example::~Example in the header file will not compile.
A similar argument applies for the move assignment operator (since the compiler-generated version needs to destroy the original Example::Impl) and for the move constructor (since the compiler-generated version needs to destroy the original Example::Impl in case exceptions).

Why can I declare constructor out of the class

Consider this link. See this code:
class MyClass
{
public:
MyClass();
~MyClass();
private:
int _a;
};
MyClass::MyClass()
{
}
MyClass::~MyClass()
{
}
We can declare constructor out of the class.
Why can I declare constructor out of the class and why we should do this?
You cannot declare constructor out of the class. You are talking about constructor definition.
class MyClass
{
public:
MyClass(); // declaration
};
MyClass::MyClass() // definition
{
}
You should read this.
The main reason why you should define your constructor outside the class is for readability. It is clearer to declare your class in the Header file and define it in the source file. You can apply this rule any members of your class.
A little quote from the standard :
12.1 Constructors
struct S {
S(); // declares the constructor
};
S::S() { } // defines the constructor
You cannot. This is the constructor declaration, which has to be in the class definition:
// MyClass definition, possibly in .h file
class MyClass
{
public:
MyClass(); // default constructor declaration
...
};
and this is the constructor's definition
// MyClass default constructor definition, possibly in .cpp file
MyClass::MyClass() { }
What you are referring to is the constructor's definition. You can define it outside of the class definition to allow you to de-couple one from the other. Usually this means you put the class definition in a header file, to be included by client code, and the constructor definition (as well as other class member function definitions) in an implementation file that gets compiled. This way, users of your code have no compile time dependency on said definitions.
The main reason for defining the constructor (or any member function) outside of the class declaration is so that you can have a header file and an implementation file. This makes your code clearer to read and allows you to distrbute the interface to your class (the header file) without providing the implementation details.
You can not declare a constructor or anything part of the class, outside it, but you can define
It's a common c++ programming practise of using 2 files for 1 class
For example,
ClassG.h
class ClassG
{
public:
ClassG();
~ClassG();
void anyfunc(int anyarg);
private:
int anydata;
};
ClassG.cpp
#include"ClassG.h"
ClassG::ClassG()
{
//something
}
ClassG::~ClassG()
{
//something
}
void ClassG::anyfunc(int anyarg)
{
//something
}
General Syntax
While declaring, inside .h file type returntype methodname(args_if_any);
While defining in a .cpp file type returntype ClassName::methodname(args_if_any){}
First of all, you have your terminology confused, you need to read What is the difference between a definition and a declaration?. You can not declare a constructor outside of a class but you can define it outside of a class.
So on to the questions as you meant them:
Why can I define a constructor out of the class
Basically the standard has this to say about member functions in section 9.3.2:
A member function may be defined (8.4) in its class definition, in which case it is an inline member function (7.1.2), or it may be defined outside of its class definition if it has already been declared but not defined in its class definition.
So the standard says this is ok, next question:
why we should do this?
It makes your code cleaner and easier to digest, you can separate your declarations into header files and your implementation into source files. This previous thread Why have header files and .cpp files in C++? goes into this topic in more detail.
Yes, you can define the constructor inside the class no matter that whether you are
using .h file or .cpp file. Actually the main difference between both the file is,
header file never compile it only use for checking syntax during compilation of .cpp
file.
Method that you define inside the class by default inline function. If you define one
constructor inside the class it's fine but, if you required to define more than one
constructor then 2 problem occur
Problem 1:
As we know that, when you call inline function it will paste code in called
function that increase the code size and required more memory.
Problem 2:
Reduce the readability of code.

C++ "expected a declaration"

I'm just getting started in C++ and already I have a problem. I'm trying to make a QFile (from QTCore) called brushInput. It's saying "expected a declaration". I've looked it up and it appears to occur from syntax issues but I don't see that in my code. Does it with and without the class.
#include <QtCore>
class Ink
{
QFile *brushInput;
brushInput = new QFile("x:\Development\InkPuppet\brush.raw");
};
You can't have an assignment in a class definition. You could have a default initialization in the class definition in C++11, though:
class Ink
{
QFile* brushInput = new QFile("x:\\Development\\InkPuppet\\brush.raw");
};
However, normally I would expect that the initialization goes into a constructor:
class Ink
{
QFile* brushInput;
public:
Ink(): brushInput(new QFile("x:\\Development\\InkPuppet\\brush.raw")) {}
};
You can't make assignments inside classes, only initializations. Therefore, use the member-initializer list of your class:
class Ink
{
QFile *brushInput;
public:
Ink() : brushInput(new QFile("x:\Development\InkPuppet\brush.raw"));
};
This:
brushInput = new QFile("x:\Development\InkPuppet\brush.raw");
is a statement. Statements (other than declarations) can appear only inside function definitions, not at class or file scope.
Putting the statement inside a function definition (perhaps a constructor) determines when the statement will be executed. If you're thinking it should be executed when the object is created -- well, that's what constructors are for.
As you are clearly new to C++, here a number of things to know to get started:
In C++ there are 2 kind of source files: header files (.h) and source files (.cpp).
Everything in C++ must be both declared and implemented. These are two different things.
The general rule is that the declarations go into the header file, the implementations go into the .cpp file.
In your case:
//ink.h file
#ifndef INK_H //this avoids multiple inclusion
#define INK_H
#include <QtCore>
class QFile; //let the compiler know the QFile is defined elsewhere
class Ink
{
public: //as a rule of thumb,
//always declare the visibility of methods and member variables
Ink(); //constructor
~Ink(); //it is a good practice to always define a destructor
private:
QFile *brushInput;
};
#endif
//.cpp file
#include "ink.h"
//implementation of the constructor
Ink::Ink() :
brushInput(new QFile("x:/Development/InkPuppet/brush.raw"); //you can use forward slashes; Qt will convert to the native path separators
{}
Avoid implementations in header file
As a second rule, avoid implementations in the header file, certainly of constructors and destructors.
Implementations of methods in the header files are known as inline methods (and they have to be marked like that). As a start, avoid them, and try to implement everything in the .cpp file. When you are more familiar with C++, you can start using the 'more advanced' things.

c++ class with constructor definition but no code where it is implemented?

I have the following class in a single .h file:
class MyClass
{
protected:
MyClass();
~MyClass();
private:
MyClass(const MyClass&);
MyClass& operator=(const MyClass&);
};
inline MyClass::MyClass()
{
}
inline MyClass::~MyClass()
{
}
What seems confusing to me is that there is no code where MyClass(const MyClass&) copy constructor and MyClass& operator=(const MyClass&) assignment operator overloading are implemented. The class just has the definitions but there is nothing else.
I've seen this in a code that I'm analyzing and it compiles perfectly. I'm new with C++ and in all the examples I've seen I found both the definition in the class and the implementation below or in a separate .cpp file
So, any one could explain why this code compiles and why would you include just the declaration of a function but not its implementation?
Thank you!!
Copy construction and assignment have been explicitly forbidden by the author.
If it is used externally, it will be an error (because it is private). If it is referenced internally or by a friend, then it will produce a link error because the definition does not exist.
In C++11, this is more clearly written as:
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
Here, the compiler will note this at compilation - no linker errors and clear intent without additional documentation :)
The code will compile if the Functions are defined but not used. If they are defined and never used the optimiser will remove them. However if they are used then you will get a linker error.
It is bad practise to define a function and not fill it out. Especially if someone else is going to be using this code.
Although, chris makes a good point, in the comments. It may be useful if you don't want people using the default function. This is also why it lies in the private section, when something like copy or = should be publicly normally.
If you explicitly define a constructor you disable all other implicit constructors. So this has implications and can be useful in many situations. However I see no reason to define and leave empty the destructor (which is not even declared virtual).

Must provide destructor in the PIMPL

// main_pimpl_sample.cpp
#include "pimpl_sample.hpp"
using namespace std;
int main()
{
pimpl_sample p;
return 0;
}
// pimpl_sample.cpp
#include "pimpl_sample.hpp"
struct pimpl_sample::impl {
};
pimpl_sample::pimpl_sample()
: pimpl_(new impl) {
}
// pimpl_sample::~pimpl_sample()
// cause problem if missed
// {}
// pimpl_sample.hpp
#if !defined (PIMPL_SAMPLE)
#define PIMPL_SAMPLE
#include <boost/scoped_ptr.hpp>
class pimpl_sample {
struct impl;
boost::scoped_ptr<impl> pimpl_;
public:
pimpl_sample();
//~pimpl_sample(); cause problem if missed
void do_something();
};
#endif
~/Documents/C++/boost $ g++ --version
g++ (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
~/Documents/C++/boost $ g++ -o main_pimpl_sample main_pimpl_sample.cpp pimpl_sample.cpp pimpl_sample.hpp
In file included from /usr/include/boost/smart_ptr/scoped_ptr.hpp:15:0,
from /usr/include/boost/scoped_ptr.hpp:14,
from pimpl_sample.hpp:6,
from main_pimpl_sample.cpp:2:
/usr/include/boost/checked_delete.hpp: In function ‘void boost::checked_delete(T*) [with T = pimpl_sample::impl]’:
/usr/include/boost/smart_ptr/scoped_ptr.hpp:80:9: instantiated from ‘boost::scoped_ptr<T>::~scoped_ptr() [with T = pimpl_sample::impl]’
pimpl_sample.hpp:8:20: instantiated from here
/usr/include/boost/checked_delete.hpp:32:58: error: invalid application of ‘sizeof’ to incomplete type ‘pimpl_sample::impl’
/usr/include/boost/checked_delete.hpp:32:58: error: creating array with negative size (‘-0x00000000000000001’)
The solution to above compilation error is to manually provide a destructor. The indicated reason is as follows:
you must still remember to define the destructor manually; the reason
is that at the time the compiler generates an implicit destructor, the
type impl is incomplete, so its destructor isn't called.
Question> I still have difficulties to absorb the above idea and would like to know a little detail why we have to provide a manual destructor here.
Thank you
TL;DR Declare an explicit destructor and implement it in a code module (not in the header file).
If you don't create the destructor, then the compiler creates an empty automatic destructor in every translation unit which tries to destroy an object of this class. You'd get equivalent behaviour if you defined an empty inline destructor in the class header.
This causes an error because the destructor is also responsible for calling destructors of all the class' fields, which - in order - needs the instantiation of the method template boost::scoped_ptr<impl>::~scoped_ptr();. This template, in turn, cannot be instantiated then because it tries to delete an object of type impl, which is only forward declared in that scope (and you need a full definition to know how to delete this object.
OTOH, if you declare the non-inline constructor in the header, its code is only generated in pimpl_sample.cpp, where also lies the definition of impl, so the scoped_ptr's destructor can be instantiated successfully.
Other translation units then only call pimpl_sample's destructor as an external method, so they don't need to generate it and instantiate scoped_ptr's destructor on their own.