我在头文件中有一些代码如下:
#include <memory>
class Thing;
class MyClass
{
std::unique_ptr< Thing > my_thing;
};
Run Code Online (Sandbox Code Playgroud)
如果我有一个CPP这个头不包含的Thing类型定义,那么这并不在VS2010 SP1的编译:
1> C:\ Program Files(x86)\ Microsoft Visual Studio 10.0\VC\include\memory(2067):错误C2027:使用未定义类型'Thing'
替换std::unique_ptr为std::shared_ptr和编译.
所以,我猜这是当前VS2010 std::unique_ptr的实现,需要完整的定义,而且完全依赖于实现.
或者是吗?它的标准要求中是否有某些东西使得std::unique_ptr实施只能使用前向声明?感觉很奇怪,因为它应该只有一个指针Thing,不应该吗?
首先,我知道unique_ptr <>和转发声明的一般问题,如使用unique_ptr的转发声明?.
考虑这三个文件:
啊
#include <memory>
#include <vector>
class B;
class A
{
public:
~A();
private:
std::unique_ptr<B> m_tilesets;
};
Run Code Online (Sandbox Code Playgroud)
C.cpp
#include "A.h"
class B {
};
A::~A() {
}
Run Code Online (Sandbox Code Playgroud)
main.cpp中
#include <memory>
#include "A.h"
int main() {
std::unique_ptr<A> m_result(new A());
}
Run Code Online (Sandbox Code Playgroud)
发出会g++ -std=c++11 main.cpp C.cpp产生以下错误:
In file included from /usr/include/c++/4.8/memory:81:0,
from main.cpp:1:
/usr/include/c++/4.8/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = B]’:
/usr/include/c++/4.8/bits/unique_ptr.h:184:16: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = B; _Dp = std::default_delete<B>]’
A.h:6:7: …Run Code Online (Sandbox Code Playgroud) 我已经在这里和这里检查了问题,但仍然无法弄清楚出了什么问题.
这是调用代码:
#include "lib.h"
using namespace lib;
int
main(const int argc, const char *argv[])
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是lib代码:
#ifndef lib_h
#define lib_h
#include <string>
#include <vector>
#include <memory>
namespace lib
{
class Foo_impl;
class Foo
{
public:
Foo();
~Foo();
private:
Foo(const Foo&);
Foo& operator=(const Foo&);
std::unique_ptr<Foo_impl> m_impl = nullptr;
friend class Foo_impl;
};
} // namespace
#endif
Run Code Online (Sandbox Code Playgroud)
clang ++给了我这个错误:
将'sizeof'无效应用于不完整类型'lib :: Foo_impl'
注意:在成员函数'std :: default_delete :: operator()'的实例化中请求
你可以看到我已经特别声明了Foo析构函数.我还缺少什么?
在下面的代码中,是避免编译错误并在A.cpp中手动实现移动构造函数/赋值的Bh的唯一方法吗?
// A.h
#include <memory>
class B; // implementation somewhere in B.h/B.cpp
class A
{
public:
A() = default;
~A() = default;
A(const A&) = delete;
A& operator=(const A&) = delete;
A(A&&) = default;
A& operator=(A&&) = default;
private:
std::unique_ptr<B> m_b;
};
Run Code Online (Sandbox Code Playgroud)
Visual Studio 2015提供了"错误C2027:使用未定义类型",因为std :: unique_ptr的移动构造函数/赋值运算符调用m_b上的删除器(试图调用B的析构函数),这在此时显然是未知的.
我试图使用带有前向声明的unique_ptr类成员.众多消息来源称例如使用unique_ptr进行前向声明?声明非内联析构函数应该足够了,但在VS2013和GCC 5.3.1中似乎不是这种情况.我没有测试其他编译器.
例:
#include <memory>
class B;
class A {
public:
//A();
~A();
private:
std::unique_ptr<B> b;
};
//class B { };
int main() {
A a;
}
Run Code Online (Sandbox Code Playgroud)
我只能在取消注释ctor声明或类B声明后才能编译此代码.否则在VS2013上我收到错误
error C2338: can't delete an incomplete type
Run Code Online (Sandbox Code Playgroud)
关于GCC错误:
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' …Run Code Online (Sandbox Code Playgroud) 我已经读过了std :: unique_ptr <T>需要知道T的完整定义吗?和unique_ptr转发声明?,但我的问题更具体.
以下编译:
// Compile with $ g++ -std=c++11 -c <filename>
#include <memory>
class A; // fwd declaration
class AUser
{
AUser(); // defined elsewhere
~AUser(); // defined elsewhere
std::unique_ptr<A> m_a;
};
Run Code Online (Sandbox Code Playgroud)
以下不是:
// Compile with $ g++ -std=c++11 -c <filename>
#include <memory>
class A; // fwd declaration
class AUser
{
AUser(); // defined elsewhere
~AUser(); // defined elsewhere
std::unique_ptr<A> m_a{nullptr};
};
Run Code Online (Sandbox Code Playgroud)
错误
$ g++ -std=c++11 -c fwd_decl_u_ptr.cpp
In file included from /usr/include/c++/4.7/memory:86:0,
from …Run Code Online (Sandbox Code Playgroud) 根据这个问题,如果所有构造函数和析构函数都不是内联的(则需要完全定义的类型),则可以转发声明智能指针。当未提供析构函数时,编译器将声明一个析构函数并提供内联定义,该定义随后要求标头中完全已知智能指针中的类型。这同样适用于默认构造函数。
然而,我发现它也适用于继承的构造函数,这对我来说有点令人困惑。考虑:
class Base
{
public:
Base(); //defined in cpp
};
class SomeClass;
class Derived : public Base
{
using Base::Base;
~Derived(); //defined in cpp
std::unique_ptr<SomeClass> ptr;
};
Run Code Online (Sandbox Code Playgroud)
Derived除非显式声明构造函数并仅在源文件中定义,否则不会编译。为什么?构造函数Base不是内联的,据我所知,using 指令应该以与其他成员类似的方式导致构造函数的“继承”。或者编译器是否将其解释为“为我声明与中相同的构造函数Base并内联定义它们”?
谁能告诉我C ++编译器何时引发“不完整的类型错误”?
注意:我故意将这个问题留给了一些开放的答案,以便我自己调试代码。
我来自 Java,它有一种不同的方式来处理私有内容,并且必须隐藏类实现,并且它还有一个垃圾收集器,这意味着不需要析构函数。
我学习了如何在 C++ 中实现类的基础知识,但在使用 pimpl 习惯用法时,我需要更好地理解如何实现类,特别是构造函数和析构函数。
.hpp 文件:
class MyClass{
public:
MyClass();
MyClass(std::vector<int>& arr);
~MyClass();
private:
struct Impl;
Impl* pimpl;
};
Run Code Online (Sandbox Code Playgroud)
.cpp 文件:
#include "MyClass.hpp"
using namespace std;
struct MyClass::Impl{
vector<int> arr;
int var;
};
Run Code Online (Sandbox Code Playgroud)
我使用 pimpl 惯用法编写了我需要处理的类的示例代码(这意味着我无法更改 pimpl 惯用法的使用方式),我正在寻找这些问题的答案:
MyClass::MyClass(){}
Run Code Online (Sandbox Code Playgroud)
MyClass::MyClass(vector<int>& arr,int var){}
Run Code Online (Sandbox Code Playgroud)
MyClass::~MyClass(){}
Run Code Online (Sandbox Code Playgroud)
编辑:
我会怎么做:
MyClass::MyClass(): pimpl(new Impl) {}
MyClass::MyClass(vector<int>& arr,int var): pimpl(new Impl) {
pimpl->arr=arr;
pimpl->var=var;
}
MyClass::~MyClass(){
delete pimpl;
}
Run Code Online (Sandbox Code Playgroud)