This question already has answers here:
Unique_ptr and forward declaration
(2 answers)
Closed 6 years ago.
I was trying to use unique_ptr class member with forward declaration. As numerous sources says e.g. Forward declaration with unique_ptr? it should be sufficient to declare non inline destructor, but it seems not to be a case in VS2013 and GCC 5.3.1. I didn't test other compilers.
Example:
#include <memory>
class B;
class A {
public:
//A();
~A();
private:
std::unique_ptr<B> b;
};
//class B { };
int main() {
A a;
}
I can make this code compile only after uncommenting the ctor declaration or the class B declaration. Otherwise on VS2013 I get error
error C2338: can't delete an incomplete type
on GCC error:
In file included from /usr/local/include/c++/5.3.0/memory:81:0,
from main.cpp:1:
/usr/local/include/c++/5.3.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = B]':
/usr/local/include/c++/5.3.0/bits/unique_ptr.h:236:17: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = B; _Dp = std::default_delete<B>]'
main.cpp:5:7: required from here
/usr/local/include/c++/5.3.0/bits/unique_ptr.h:74:22: error: invalid application of 'sizeof' to incomplete type 'B'
static_assert(sizeof(_Tp)>0,
^
Why is this?
The destructor of class A must know the definition of class B. A forward declaration of class B is okay as longs as the implementation file of the constructor/destructor of A knows the definition of class B. If your implementation is (implicitly) in a header file then you need a definition of B in your header file. You may study Pimpl from Herb Sutter.
Related
This question already has answers here:
C++ class declaration after using it
(3 answers)
What are forward declarations in C++?
(8 answers)
Closed 3 months ago.
I'm sure that this has been asked, but I cannot find the question or answer, so here is the minimal code I tried to compile.
// goof4.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
class A;
class B
{
public:
A func() { return A{}; }
};
class A
{
};
int main()
{
B b;
auto a = b.func();
}
The declaration of B::func gives a "use of undefined type 'A' Error C2027 in MSVC 2022 using /std:c++20. I would have thought that the forward declaration of "class A" would have allowed the compiler to work on B::func until such time as class A was defined. Any help?
Because you have the function body using the (at that point) undefined type A in the class B itself and in a function body the type must already be defined.
just do A funct(); in the class B itself
and put the function body and after defining A,
A B::funct() { return A{}; }
https://ide.geeksforgeeks.org/2db37ea7-a62c-487b-8af5-10af8cebc3c6
This question already has answers here:
Can typedef names be used to declare or define constructors?
(2 answers)
Closed 7 months ago.
This minimum reproducible piece of code
class MyClass
{
public:
explicit MyClass();
~MyClass();
};
using MyClassAlias = MyClass;
MyClassAlias::MyClassAlias()
{
}
MyClassAlias::~MyClassAlias()
{
}
int main()
{
MyClassAlias obj;
return 0;
}
gives the error:
a.cpp:11:1: error: ISO C++ forbids declaration of ‘MyClassAlias’ with no type [-fpermissive]
11 | MyClassAlias::MyClassAlias()
| ^~~~~~~~~~~~
a.cpp:11:1: error: no declaration matches ‘int MyClass::MyClassAlias()’
a.cpp:11:1: note: no functions named ‘int MyClass::MyClassAlias()’
a.cpp:1:7: note: ‘class MyClass’ defined here
1 | class MyClass
| ^~~~~~~
Only if I replace MyClassAlias::MyClassAlias() with MyClassAlias::MyClass(), it gets cured. At the same time, as you can see, it is okay to have MyClassAlias::~MyClassAlias() (the compiler gives no error).
Is there any way to fix this: to have consistency in naming?
The "names" (although these are not names in the technical sense of the standard) of the constructor and destructor are MyClass and ~MyClass respectively. They are based on the injected class name. You need to use these two to define them or write any declaration for them. You cannot use an alias name for these.
The same does not apply to the class name before the ::. It can be the name of an alias.
It seems that GCC accepts the alias as well for the destructor definition, but as far as I can tell that is not standard-conforming.
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.
This question already has answers here:
C++'s most vexing parse again [duplicate]
(2 answers)
Closed 8 years ago.
This title may not be completely accurate--it's based on my best guess on what is happening and I figured it was better than "Can someone explain what is happening with this code?"
Anyway, I have this code:
class Class1 { };
class Class2
{
public:
Class2(Class1 other){}
};
void func(Class2 x){}
int main()
{
Class2 x(Class1());
func(x); //Compile Error
Class1 y1;
Class2 y2(y1);
func(y2); //Compiles fine
return 0;
}
So when I compile it, the line marked as "Compile Error" provides an error in g++ 4.9:
main.cpp: In function ‘int main()’:
main.cpp:14:10: error: could not convert ‘x’ from ‘Class2 (*)(Class1 (*)())’ to ‘Class2’
func(x);
^
clang++ 3.4.1 provides a similar error.
My best guess is that it thinks that "x" is some sort of function that returns a Class2, instead of a Class2 itself, but...why is this happening? I would think that the call to Class1 returns some anonymous Class1 which is passed into Class2's constructor.
Class2 x(Class1()); is a function declaration due to a vexing parse (google skills come in handy here).
Alternative:
Class2 x((Class1()));
Class2 x{Class1()};
This is because this line
Class2 x( Class1());
declares a function actually and not an object. This is known as vexing parse.
To avoid this issue you should write:
Class2 x((Class1()));
or
Class1 y;
Class2 x( y);
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.