Forward declaration with unique_ptr? [duplicate] - c++

This question already has answers here:
Is std::unique_ptr<T> required to know the full definition of T?
(9 answers)
Closed 8 years ago.
I have found it useful to use forward declaration of classes in combination with std::unique_ptr as in the code below. It compiles and works with GCC, but the whole thing seem kind of strange, and I wonder if this is standard behaviour (i.e. required by the standard)? Since B isn't a complete type when I declare the unique_ptr.
A.hpp
#include <memory>
class B;
class A {
std::unique_ptr<B> myptr;
// B::~B() can't be seen from here
public:
~A();
};
A.cpp
#include "B.hpp"
//B.hpp has to be included, otherwise it doesn't work.
A::~A() = default; // without this line, it won't compile
// however, any destructor definiton will do.
I suspect this has to do with the destructor (and therefore the need to call the destructor of unique_ptr<B>) is defined in a specific compilation unit (A.cpp).

It's explicitly legal. The rule is that the types used to instantiate
a template in the standard library must be complete, unless otherwise
specified. In the case of unique_ptr, §20.7.1/5 says “[...] The
template parameter T of unique_ptr may be an incomplete type.”
There are certain operations on the pointer which require a complete
type; in particular, when the object will actually be destructed (at
least with the default deleter). In your example, for example, if
A::~A() were inline, this might cause problems. (Note that if you
don't declare the destructor yourself, it will be inline. Which
partially defeats the purpose of using std::unique_ptr.)

Related

C++ constexpr final virtual functions [duplicate]

This question already has answers here:
Can virtual functions be constexpr?
(3 answers)
Closed 1 year ago.
I'm implementing a pure virtual function in a C++ derived class, and mark the method final. I would also like to mark the function constexpr, but it appears the standard doesn't allow this.
Is there any practical reason why it would be difficult for compilers to implement this? Or is such a feature omitted due to the usual "this feature wasn't deemed to be important enough to add to the standard" thinking?
Based on the comments, it seems my original question didn't make it clear I am asking about constexpr final functions. The following code illustrates what I am trying to compile:
struct A {
virtual int foo() const;
};
struct B : public A {
// Note that this function is final, and is therefore no longer
// polymorphic in types derived from B (e.g., the function call
// no longer requires a lookup in the virtual method table
// when the compile-time type is known to be derived from B)
constexpr int foo() const final {
return 0;
}
};
Note that this was flagged as a duplicate of Can virtual functions be constexpr?, since in C++20, the above code would compile with or without the final keyword.
C++20 adds support for this code.
On godbolt, we can try it out: https://godbolt.org/z/f64e93dzY
It looks like this is Defect Report 647

Why no constructors are called? [duplicate]

This question already has an answer here:
Most vexing parse
(1 answer)
Closed 2 years ago.
Here C() is a temporary object which should have been created with no-arg constructor and then I expected a call to move constructor. Yet none of them happened. Can someone exmplain why?
#include <iostream>
using namespace std;
class C{
public:
C(){std::cout<<"No arg\n";}
C(const C& r){std:cout<<"Copy Cons\n";}
C(C&& r){std:cout<<"Move Cons\n";}
};
int main() {
C c(C());
}
The statement C c(C()); is actually a function declaration for a function called c that returns C and takes a function (unnamed) as a parameter that returns a C and takes no parameters.
In other words, it's purely declarative and has no effect on the program.
This is an example of the most vexing parse.
Even if it we fixed that (with C c((C())) or C c{C()}) , pre-C++17 most compilers used permission granted by the language to optimise away that "extra" temporary object (and since C++17 they must do so), so at best you'd probably only see the output from a single default constructor invocation.

Why is a forward declaration not enough even if the data type is never used [duplicate]

This question already has answers here:
When can I use a forward declaration?
(13 answers)
Closed 5 years ago.
I know that similar questions have already been asked and there are answers describing that in the situations describe below forward declaration is not enough. However, these answers do NOT tell WHY it is not enough. Therefore, I don't think that this is a duplicated question.
I have some difficulties to understand why the compiler has to see the definition of a data type (a foward declaration is not sufficient) in the following situation:
Let's consider we have a simple "main.cpp" as shown below, which does
absolutely nothing except including the header file "MyClass.hpp"
#include <MyClass.hpp>
int main(int argc, char **argv)
{
return 0;
}
Now, let's consider that the content of "MyClass.hpp" looks as follows:
#include <vector>
class Data1;
class MyClass
{
public:
MyClass(); // default constructor
MyClass(MyClass const & p_other); // copy constructor
MyClass(MyClass && p_other); // move constructor
~MyClass(); // destructor
MyClass & operator=(MyClass const & p_rhs); // copy assignment
MyClass & operator=(MyClass && p_rhs); // move assignment
private:
Data1 * m_a; // forward decl. always OK
Data1 m_b; // forward decl. always not OK
std::vector<Data1> m_c; // forward decl. OK if MyClass is not instantiated
};
MyClass contains several member variables:
"m_a" is a pointer to "Data1",
"m_b" is an instance of "Data1",
"m_c" is a vector with elements of type "Data1".
The definition of "Data1" is neither included in "MyClass.hpp" nor in "main.cpp". It is just forward declared.
The compiler never has a problem with member variable "m_a", it doesn't require its definition for compiling "main.cpp" -- even if we would intantiate "MyClass".
Because we are not instantiating "MyClass", the compiler also doesn't have a problem with member variable "m_c". It also does not require the definition of "Data1" in this case.
However, the compiler has a problem with member variable "m_b":
Impl1.hpp:16:24: error: field 'm_b' has incomplete type 'Data1'
My simple question is: why?
Please consider that we have user-defined default constructor, copy constructor,
move constructor, a user-defined destructor, and user-defined copy assigment
operator and move assignment operator, i.e., the compiler doesn't have to
generate code for any of these constructors/methods. So for what purpose does
the compiler need to see the definition of "Data1" when compiling only "main.cpp"?
Does anybody know the answer?
The size of MyClass depends on the size of Data1, which can only be known from the definition of Data1. That's why you cannot have incomplete types as fields in your types.

Initializing a variable using default constructor [duplicate]

This question already has answers here:
Default constructor with empty brackets
(9 answers)
Closed 7 years ago.
I'm pretty new to c++, i'm now trying to learn all the basics,
I know when default constructors are called, but when i tried different syntax it doesn't work like i expected.
Look at the following code:
class a;
class b();
class c(NULL);
'class' is a class i created with default constructor,
for a and c everything works well, but for b it just won't recognize the variable as a class member.
As i see it b and c are basically the same, what's wrong than?
Thanks!
Don't name your class "class", as it is a reserved name.
As for C++, if the constructor takes no parameters, you instantiate it using
Foo a; // note, if you are using c++11, you can do Foo a{};
As opposed to:
Foo b();
Which actually does something totally unexpected*, and declares a function named b that returns a Foo instance.
As for Foo c(null), it won't compile as there is no default constructor that takes an argument.
* It is referred to as "the most vexing parse", though I find that to be an exaggeration. It can certainly catch you by surprise, but just knowing that you can declare a function prototype inside a function, should be enough to remove the "vexing" aspect.
In other words int getMyInt(); is obviously a function prototype when placed outside any function definitions. However, since this is also the case when inside a function definition, int getMyInt(); doesn't do anything it wouldn't normally do... which is to define a function prototype getMyInt that returns an integer.
b is interpreted as a declaration of a function taking no arguments and returning an object of type class.
This is known as the most vexing parse. Edit: This is not the most vexing parse.

Pimpl with smart ptr - Why constructor/destructor needed [duplicate]

This question already has answers here:
std::unique_ptr with an incomplete type won't compile
(7 answers)
Closed 9 years ago.
Lets consider following example (using c++11)
A.hpp:
#include <memory>
class A
{
public:
//A();
//~A();
private:
struct AImpl;
std::unique_ptr<AImpl> pImpl;
};
main.cpp:
#include "A.hpp"
int main()
{
A a;
}
Using default constructor and destructor. Does not compile. Following error occurs:
In file included from /usr/include/c++/4.8/memory:81:0,
from A.hpp:2,
from main.cpp:2: /usr/include/c++/4.8/bits/unique_ptr.h: In instantiation of 'void
std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp =
A::AImpl]': /usr/include/c++/4.8/bits/unique_ptr.h:184:16: required
from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = A::AImpl;
_Dp = std::default_delete]' A.hpp:3:7: required from here /usr/include/c++/4.8/bits/unique_ptr.h:65:22: error: invalid
application of 'sizeof' to incomplete type 'A::AImpl'
static_assert(sizeof(_Tp)>0,
A similar error occurs when using boost::scoped_ptr instead of std::unique_ptr. Do I understand this correctly - it means, that the forward declaration of AImpl is not enough?
When adding constructor and destructor, everything works fine. What is the reason? Is it because the defaults are inlined an thus do not see the size of AImpl? And when adding constructor and destructor, the compiler assumes, that those definitions know the size of AImpl?
The unique_ptr destructor needs to know the full definition of AImpl, because it deletes it. So the question is, where does the unique_ptr destructor sit? It's a template, so the question is about the instantiation point.
The destructor is instantiated when it is first used. Both the constructor and the destructor of the containing class use it (the constructor needs it if its body throws an exception). So the unique_ptr destructor is instantiated where A's constructor or destructor are placed, whichever comes first.
If you default those special members, they are generated immediately after the class body, i.e. in the header, where the size of AImpl is not known.
If you instead declare them in the class and then put definitions (you may =default those definitions) in the .cpp, after the full definition of AImpl, then the unique_ptr destructor is instantiated there.