Where should a default destructor C++11 style go, header or cpp? - c++11

In C++11 a default implementation of constructor(s), destructor and copy/move operators can be specified with "= default". Where to put the "= default", in header file, where the class definition is, or in the source file (cpp)?
In header file Test.h:
class Test
{
public:
~Test() = default;
};
In source file Test.cpp:
class Test
{
public:
~Test();
};
#include "Test.h"
Test::~Test() = default;

I have to disagree with rubenvb. You aren't forced to put the explicit default destructor in the header file.
In fact, there is a use case for which it's perfectly valid (and necessary) to put the explicit default destructor in the .cpp file.
Consider the case where you forward declare a class in the header file, and use it with one of the smart pointers templates. As the implicit destructor doesn't have the complete declaration of the forward declared class, it cannot properly do its deletion. Therefore, you need to move the destructor definition to the C++ file, where you should have access to the complete declaration.
In A.hpp:
#pragma once
#include <memory>
class B;
class A
{
private:
std::unique_ptr<B> my_b;
public:
// ~A() = default;
// defining the default destructor would fail as
// class B is still a partial class here
~A();
};
In A.cpp:
#include "A.hpp"
// the previously forward declared class B is now included here
#include "B.hpp"
// we can use the default destructor here as B is
// no longer a partial class
A::~A() = default;

You can do both:
in the first case (header) the destructor will be considered as non-user defined
in the second case (cpp) the compiler will consider it as user defined.
A user-provided destructor is non-trivial, making the class itself necessarily non-trivial.
Unless you have a good reason to for the second option, putting it in the header is the usual way to go.

You must put it in the header (well, wherever the class definition is located and the destructor is declared) or else anyone using your class won't know about this behaviour, including the compiler, which leads to obvious wrong behaviour on its part.

Related

Static casting to unique_ptr

I have a head file which needs to hide some internals for complexity and "secrecy" reasons. I've therefore a raw void pointer declared in the oublic header, inside the code there are static casts to convert the raw pointer to it's actual type.
Now due to general memory management changes I need to change the type internally to a unique_ptr (it's coming from an object factory now as a unique_ptr, previously it was a raw pointer).
So in my header I have this:
class SomeClass {
private:
void *_hiddenTypeInstance;
}
Is it possible to static-cast this _hiddenTypeInstance to an internally known unique_ptr type?
This is not a direct answer of what you wanted, but a proposal how to do things nicer:) You can actually still use the memory semantics of std::unique_ptr with hiding the internals and without using the ugly void*. As others have mentioned, you should look into PIMPL, but to summarize:
Forward declare the internal type in the public header
Use std::unique_ptr with that type and provide a dtor for the class which holds that member (otherwise you will get compilation errors because a default dtor will be generated, that will try to delete the forward declared class and will fail to do so).
This would look something like this:
#include <memory>
class CPrivate; // Forward declare the internal class
class CPublic
{
public:
// You need the dtor here, since when you implement it in the .cpp of your library,
// where the definition of CPrivate is known, the dtor of std::unique_ptr will know how to delete it.
// If you do not put the dtor here, a default one will be generated here which invokes the dtor of std::unique_ptr, and here
// since CPrivate is forward declared the dtor of std::unique_ptr will not know how to delete it and you will get an error
~CPublic();
private:
std::unique_ptr<CPrivate> m_pPrivate;
}
By using this, you can then escape the casts inside the implementation from the void* to the actual type.
As for the original question - you can always cast void* to a std::unique_ptr<T>* (a pointer to a unique_ptr). But I would advise to evaluate the solution above. Because the void* thing moves away all type strictness - e.g what happens if someone changes T ?
if i understand you problem in a correct way: here is what you can do. This example is just for understanding of a concept. You can use it in your own code. Since I dont have the entire code I cant write exact solution.
class SomeClass {
private:
void *_hiddenTypeInstance;
public:
std::unique_ptr<int> foo() {
int a;
a = 2;
return std::unique_ptr<int>(&a);
}
void bar() {
std::unique_ptr<int> temp_hidden_type_instance;
temp_hidden_type_instance = std::unique_ptr<int>(static_cast<int*>(_hiddenTypeInstance));
temp_hidden_type_instance = foo();
}
};

Why does making this virtual destructor inline fix a linker issue?

If I have a pure virtual class InterfaceA that consists solely of a pure virtual destructor, why do I have to define the destructor as inline? I I don't I get an error when I try to link it.
Below is an admittedly contrived example, however it illustrates the point. The point does not compile for me using cmake and g++. However, if I change the InterfaceA destructor definition as follows - inline InterfaceA::~InterfaceA(){}; then it compiles.
Why is this? What does the inline keyword do?
// InterfaceA.h, include guards ommitted for clarity
class InterfaceA
{
public:
virtual ~InterfaceA() = 0;
};
InterfaceA::~InterfaceA(){};
// A.h, include guards ommitted for clarity
#include "InterfaceA.h"
class A : public InterfaceA
{
public:
A(int val)
: myVal(val){};
~A(){};
int myVal;
};
// AUser.h, include guards ommitted for clarity
#include "InterfaceA.h"
class AUser
{
public:
AUser(InterfaceA& anA)
: myA(anA){};
~AUser(){};
int getVal() const;
private:
InterfaceA& myA;
};
// AUser.cpp
#include "AUser.h"
#include "A.h"
int AUser::getVal() const
{
A& anA = static_cast<A&>(myA);
return anA.myVal;
}
// main.cpp
#include "AUser.h"
#include "A.h"
#include <iostream>
int main(){
A anA(1);
AUser user(anA);
std::cout << "value = " << user.getVal() << std::endl;
return 0;
}
You have to use the inline keyword when defining functions in header files. If you do not, and the file is included in more than one translation unit, the function will be defined twice (or more times).
The linker error is probably something like "Symbol ... is multiply defined" right?
If you defined the member function in the body of the class, it would be implicitly inline and it would also work.
See this answer
To answer the question "What does the inline keyword do?":
In the old days it would be used to ask the compiler to inline functions i.e. insert the code whenever the function is used instead of adding a function call. Eventually it turned into a simple suggestion since compiler optimizers became more knowledgeable about which functions were inline candidates. These days it is used almost exclusively to define functions in header files that must have external linkage.
inline means that compiler is allowed to add code directly to where the function was called. It also removes function from external linkage, so both your compile units would have local version of.. pure destructor.
// InterfaceA.h, include guards ommitted for clarity
class InterfaceA
{
public:
virtual ~InterfaceA() = 0;
};
You declare destructor virtual, so compiler almost never would make it inline. Why? because virtual functions are called through vtable - a internal working of virtual functions system, vtable most likely implemented as an array of pointers to member functions. If function is inlined, it would have no address, no legal pointer. If attempt to get address of function is taken, then compiler silently disregards inline keyword. The other effect will be still in place: inlined destructor stops to be visible to linker.
It may look like declaring pure virtual destructor looks like oxymoron , but it isn't. The pure destructor is kind of destructor that would be always called without causing UB. Its presence would make class abstract, but the implicit call in sequence of destructor calls would still happen. If you didn't declare destructor body, it would lead to an UB, e.g. purecall exception on Windows.
If you don't need an abstract base class, then inline definition will suffice:
class InterfaceA
{
public:
virtual ~InterfaceA() {}
};
that is treated by compiler as inline as well, but mixing inline definition and pure member declaration is not allowed.

Why I got 'unknown size' error when I use '=default' for the destructor?

Inner.hpp
#pragma once
#include <vector>
class Outter
{
public:
Outter();
~Outter() = default;
private:
class Inner;
std::vector<Inner> list;
};
Inner.cpp
#include "Inner.hpp"
#include <iostream>
class Outter::Inner
{
public:
Inner() : x(0), y(0), z(0) {}
~Inner() {}
private:
int x, y, z;
};
Outter::Outter()
{
std::cout << "Constructor\n";
}
//Outter::~Outter()
//{
// std::cout << "Destructor\n";
//}
InnerMain.cpp
#include "Inner.hpp"
int main()
{
Outter test;
}
When I compile above codes, I got an 'unknown size' error for the class Outter::Inner.
But if I change the 'default' destructor of Outter class to the implementation in Inner.cpp (commented in the above), then the error is cleared.
Why does this happen when I use '=default' destructor?
Please let me know.
Thanks.
As a result, in this case, '=default' was not important.
The implementation should be placed in .cpp file to make the compiler know the size of class Outter::Inner.
Forward declaration is not enough here. std::vector needs to know exactly what is the size of the inner class at compile time. Actually, the std::vector destructor who needs to know what is the real size of the inner class.
You have some solutions like using pointers to Inner class (if you want to keep your destructor in hpp):
std::vector<Inner*> list;
Or alternatively, move your destructor to the cpp class like what you did in the commented code. BTW, please be aware that you can set your destructor to default in the cpp file:
Outter::~Outter()=default;
Why does this happen when I use '=default' destructor?
Because of the destructor of std::vector needs to know the size. You defined the destructor of the class containing the std::vector in the header file where no information about the real size of the inner. However, when you put the definition of the destructor in the cpp file, the compiler now knows what is the actual size of inner and std::vector destructor will not complain.

c++11 forwarddeclare thread,mutex,chrono

I am aware that we should prefer to forward declare everything in header files, if possible but what about STL?
I have found that for iostream there is iosfwd.
What if i want to have a mutex declared in my class, like this:
class MyClass
{
.....
private:
std::mutex mMutex;
};
Should I include mutex header in my class header?
Or is there way to forwarddeclare it, like:
class std::mutex;
class MyClass{...};
Same goes for chrono, and thread as well.
Any thoughts on that is appreacited. Thanks!
There is no portable way to forward declare std::objects, except as specified (e.g. <iosfwd>). And there are no forwarding headers for mutex, thread or chrono.
The C++ 11 standard states that forward declaring classes that are part of the std namespace cannot be forward declared (section 17.6.4.2.1):
The behavior of a C++ program is undefined if it adds declarations or
definitions to namespace std or to a namespace within namespace std
unless otherwise specified.
However for some reason the following piece of code does compile and run.
.h:
#pragma once
// Forward declaration of thread class that is part of the std namespace
namespace std
{
class thread;
}
// Example declaration of a class using the forward declared class
class ExampleClass
{
private:
std::thread * _thread;
void ThreadFunction(){}
}
.cpp
#include "ExampleClass.h"
#include <thread>
ExampleClass::ExampleClass() :
_thread(new std::thread(std::bind(&ExampleClass::ThreadFunction, this)))
{
}
I compiled the code using visual studio 2015, perhaps that the C++ 11 standard statement no longer applies to C++14/17/20?

C++11 implicit copy constructor while implementing explicitly a constructor

I ran into a problem. I implemented a constructor for a class, but why are implicitly generated the other constructors, like the copy one?
I thought, that if I define a constructor explicitly, then the compiler doesn't generates implicitly other ones. I'm really hoping, that this a VC++ specific thing, and that this code doesn't conforms to ISO:IEC C++11:
class Foo
{
int bar;
public:
Foo(int&& arg) : bar(arg) { cout << "RConstruction" << endl; }
};
int main(int, const char*[])
{
Foo f = Foo(42);
/* Create unused temporary on the stack */
Foo::Foo(f); /* calling Foo::Foo(const Foo&): this shouldn't work... */
return (0);
}
Please keep in mind, that this is a sample code, created exactly for this situation, for demonstration purposes, I expect answers only that strictly relate to this question.
That's not a move constructor, so it doesn't suppress any implicit ones.
Just like Foo(const int&) isn't a copy constructor, Foo(int&&) isn't a move constructor, it's just a constructor taking an rvalue reference.
A move constructor looks like one of:
Foo(Foo&&)
Foo(const Foo&&)
Foo(volatile Foo&&)
Foo(const volatile Foo&&)
I thought, that if I define a constructor explicitly, then the compiler doesn't generates implicitly other ones.
If you define any constructor the compiler doesn't generate the default constructor, but it still generates the others. Define the as deleted if you don't want them:
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
You did not declare a move constructor, but a regular constructor : no implicit constructor will be deleted.
A move constructor would be of the form Foo(Foo&& arg) (with any cv-qualifier on the argument)
Also note that this statement is not valid C++ :
Foo::Foo(f);
Maybe you meant :
Foo g = Foo(f);

Resources