Why I got 'unknown size' error when I use '=default' for the destructor? - c++11

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.

Related

When initializing an atomic class member it requires a 'deleted' function, but adding it would make it no longer trivially copyable

When initializing an atomic class member it requires a 'deleted' function, but adding it would make it no longer trivially copyable which is a requirement for an object/struct to be atomic. Am I just not understanding how to do this correctly, or is this a problem in the c++ standard?
Take the example below:
#include <atomic>
#include <cstdint>
template<typename T>
struct A
{
T * data;
std::atomic<uintptr_t> next;
};
template<typename T>
class B
{
std::atomic<A<T>> myA;
public:
B ( A<T> & a ) noexcept
{
myA.store(a, std::memory_order_relaxed );
}
};
int main ()
{
A<int> a;
B<int> b(a);
return 0;
}
Trying to compile this with g++ gives error: use of deleted function 'A<int>::A(const A<int>&)' myA.store(a, std::memory_order_relaxed);. My understanding of this error is that the atomic::store method is looking for that constructor in my struct A but not finding it.
Now here is what happens when I add that constructor:
#include <atomic>
#include <cstdint>
template<typename T>
struct A
{
T * data;
std::atomic<uintptr_t> next;
A(const A<T>& obj) { }
A( ) { }
};
template<typename T>
class B
{
std::atomic<A<T>> myA;
public:
B ( A<T> & a ) noexcept
{
myA.store(a, std::memory_order_relaxed );
}
};
int main ()
{
A<int> a;
B<int> b(a);
return 0;
}
I no longer receive the above compiler error but a new one coming from the requirements of the atomic class required from 'class B<int>' .... error: static assertion failed: std::atomic requires a trivially copyable type ... In other words by adding the used-defined constructors I have made my struct A a non-trivially copyable object which cannot be initialized in class B. However, without the user-defined constructors I cannot use the store method in myA.store(a, std::memory_order_relaxed).
This seems like a flaw in the design of the std::atomic class. Now maybe I am just doing something wrong because I don't have a lot of experience using C++11 and up (I'm old school). Since 11 there have been a lot of changes and the requirements seem to be a lot stricter. I'm hoping someone can tell me how to achieve what I want to achieve.
Also I cannot change std::atomic<A<T>> myA; to std::atomic<A<T>> * myA; (changed to pointer) or std::atomic<A<T>*> myA;. I realize this will compile but it will destroy the fundamental design of a class I am trying to build.
The problem here resides in the fact that std::atomic requires a trivially copiable type. This because trivially copyable types are the only sure types in C++ which can be directly copied by copying their memory contents directly (eg. through std::memcpy). Also non-formerly trivially copyable types could be safe to raw copy but no assumption can be made on this.
This is indeed important for std::atomic since copy on temporary values is made through std::memcpy, see some implementation details for Clang for example.
Now at the same time std::atomic is not copy constructible, and this is for reasonable reasons, check this answer for example, so it's implicitly not trivially copyable (nor any type which contains them).
If, absurdly, you would allow a std::atomic to contain another std::atomic, and the implementation of std::atomic contains a lock, how would you manage copying it atomically? How should it work?

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.

C++11. Move semantics for lvalue reference in return statement

In C++11/14 we have: Return value optimization, move semantics, some classes like unique_ptr which don't have copy ctor
Q1: What is a correct behavior of the code snippet below when DECLARE_COPY_CTOR is equal to 1 or to zero ?
Q2: Console application built with MSVC 2013 for code snippet below in DEBUG build for Win32 gives in console: A(), A(A&&), ~A(), ~A(). So looks like lvalue referencce "a" was used to bind to "A&&". Is it legal? I thought that only temporary objects can be a candidate for move.
Q3: In RELEASE build compiler choose to use Rvo (so output was: A(), ~A())
Is compiler free to choose is "a" in function scope is a canditate for move?
#include <stdio.h>
#include <iostream>
#include <memory>
#define DECLARE_COPY_CTOR 0
class A
{
public:
A() {puts("A()");}
~A() { puts("~A()"); }
#if DECLARE_COPY_CTOR
A(A&) { puts("A(A&)"); }
#endif
A(A&&) { puts("A(A&&)"); }
A& operator = (A&) { puts("A& operator = (A&)"); return *this; }
};
A F()
{
A a; // here a is lvalue
return a; // here a is still lvalue
}
int main()
{
auto i = F();
return 0;
}
Q1. What is a correct behavior of the code snippet below when DECLARE_COPY_CTOR is equal to 1 or to zero ?
DECLARE_COPY_CTOR has no effect on the behaviour. Copy constructor is not invoked in the program.
Q2. So looks like lvalue referencce "a"
a is an lvalue, but it isn't an lvalue reference.
Q2. Is it legal?
Yes, it is legal to return a non-copyable local lvalue. It will be moved.
Q3. Is compiler free to choose is "a" in function scope is a canditate for move?
If the type of returned local variable is movable, then it must be moved rather than copied. NRVO applies to this case, so the compiler is free to elide the move - just like it was free to elide the copy prior to c++11.

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

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.

std::unique_ptr<T> without allocating memory on heap

I wrote accidentally a statement like
std::unique_ptr<Thing> m_thing;
m_thing->DoStuff();
instead of
std::unique_ptr<Thing> m_thing(new Thing);
m_thing->DoStuff();
the first example compiles and run, which doesn't make any sense to me because m_thing is not pointing to any object. Here a slightly bigger code example.
#include <iostream>
#include <memory>
class Thing
{
public:
~Thing(){ std::cout << "destructor of class Thing\n"; }
void DoStuff(){ std::cout << "doing stuff\n"; }
};
void Foo()
{
std::unique_ptr<Thing> m_thing;
m_thing->DoStuff(); //why does this work, since i suppose m_thing to be empty?
}
int main()
{
Foo();
std::cout << "after Foo()\n";
std::cin.get();
return 0;
}
Why can the "empty" m_thing unique_ptr invoke the DoStuff()-Method of the Thing-class?
i noticed also, that the destructor of Thing-class never gets invoked when declaring m_thing
with
std::unique_ptr<Thing> m_thing;
instead of
std::unique_ptr<Thing> m_thing(new Thing);
I didn't found any explanation of this behaviour via google, so i hope maybe someone can explain to me what is happening here behind the curtains.
Your program exhibits undefined behavior. "Seems to work" is one possible manifestation of undefined behavior. It's morally equivalent to
Thing* p = NULL;
p->DoStuff();
which I predict would also compile and run. DoStuff is called with NULL for this pointer - but it doesn't actually use this, that's why it doesn't crash and burn as you expect.
DoStuff isn't virtual and doesn't access any members of your object, so you can get away with calling it (I'm pretty sure this is unspecified behavior though). The default constructor for unique_ptr initializes it to nullptr, so it doesn't allocate any memory on its own.
Oh, and the destructor of course doesn't get called because unique_ptr doesn't invoke its deleter on nullptrs.

Resources