我在头文件中有一些代码如下:
#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
,不应该吗?
在使用std::unique_ptr
自定义删除器时,我希望使用std::make_unique
而不是原始的新删除器.我正在使用VC++ 2013.在我看来,std::unique_ptr
如果您使用自定义删除器,则无法使用.我错过了什么,或者这是真的吗?
附加信息:
我正在使用a std::unique_ptr<HANDLE, custom_deleter>
来保存打开的COM端口的Windows HANDLE.
我可以为此编写一个自定义RAII类,它不会非常困难,但我看到它的使用难度/难度/难度std::unique_ptr
.
考虑用来解释一下这个典型的例子并不与前向声明做:
//in Handle.h file
class Body;
class Handle
{
public:
Handle();
~Handle() {delete impl_;}
//....
private:
Body *impl_;
};
//---------------------------------------
//in Handle.cpp file
#include "Handle.h"
class Body
{
//Non-trivial destructor here
public:
~Body () {//Do a lot of things...}
};
Handle::Handle () : impl_(new Body) {}
//---------------------------------------
//in Handle_user.cpp client code:
#include "Handle.h"
//... in some function...
{
Handle handleObj;
//Do smtg with handleObj...
//handleObj now reaches end-of-life, and BUM: Undefined behaviour
}
Run Code Online (Sandbox Code Playgroud)
我从标准中了解到这个案例正朝向UB,因为Body的析构函数是非常重要的.我想要了解的是这个的根本原因.
我的意思是,问题似乎是由Handle的dtor内联的事实"触发",因此编译器执行类似下面的"内联扩展"(这里几乎是伪代码).
inline Handle::~Handle()
{ …
Run Code Online (Sandbox Code Playgroud) c++ destructor memory-management forward-declaration delete-operator
让我们考虑以下示例(使用c ++ 11)
A.hpp:
#include <memory>
class A
{
public:
//A();
//~A();
private:
struct AImpl;
std::unique_ptr<AImpl> pImpl;
};
Run Code Online (Sandbox Code Playgroud)
main.cpp中:
#include "A.hpp"
int main()
{
A a;
}
Run Code Online (Sandbox Code Playgroud)
使用默认构造函数和析构函数.不编译.发生以下错误:
在文件中包含/usr/include/c++/4.8/memory:81:0,来自A.hpp:2,来自main.cpp:2:/usr/include/c++/4.8/bits/unique_ptr.h:实例化'void std :: default_delete <_Tp> :: operator()(_ Tp*)const [with _Tp = A :: AImpl]':/ usr /include/c++/4.8/bits/unique_ptr.h:184:16: 'std :: unique_ptr <_Tp,_Dp> ::〜unique_ptr()[与_Tp = A :: AImpl; _Dp = std :: default_delete]'A.hpp:3:7:从这里需要/usr/include/c++/4.8/bits/unique_ptr.h:65:22:错误:'sizeof'无效应用于不完整类型' A :: AImpl'static_assert
(sizeof(_Tp)> 0,
使用boost :: scoped_ptr而不是std :: unique_ptr时会发生类似的错误.我是否理解正确 - 这意味着,AImpl的前向声明是不够的?
添加构造函数和析构函数时,一切正常.是什么原因?是因为默认是内联的,因此看不到AImpl的大小?在添加构造函数和析构函数时,编译器假定这些定义知道AImpl的大小?
代码
#include <list>
#include <memory>
class B;
class A {
std::list<std::unique_ptr<B>> bs;
public:
A();
~A();
};
int main()
{
A x;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
显然编译.它没有链接因为A::A()
并且A::~A()
缺失,但这是预期的并且没有问题.更改
std::list<std::unique_ptr<B>> bs;
Run Code Online (Sandbox Code Playgroud)
应该称之为std::list
标准构造函数
list() : list(Allocator()) {}
Run Code Online (Sandbox Code Playgroud)
(C++ 14及以上)来
std::list<std::unique_ptr<B>> bs{};
Run Code Online (Sandbox Code Playgroud)
应该调用list(std :: initializer_list,const Allocator&= Allocator());
默认构造函数也是.(感谢Nicol Bolas,他正确地提到[over.match.list] 13.3.1.7)在c ++(Ubuntu 5.2.1-22ubuntu2)5.2.1 20151010和--std = c ++ 17参数中给出以下错误:
/usr/include/c++/5/bits/unique_ptr.h: In instantiation of ‘void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = B]’:
/usr/include/c++/5/bits/unique_ptr.h:236:17: required from ‘std::unique_ptr<_Tp, _Dp>::~unique_ptr() …
Run Code Online (Sandbox Code Playgroud) 只要我不将构造函数(of B
)的定义移动到头部,代码就会工作B.h
.
BH
class Imp; //<--- error here
class B{
public:
std::unique_ptr<Imp> imp;
B(); //<--- move definition to here will compile error
~B();
//// .... other functions ....
};
Run Code Online (Sandbox Code Playgroud)
B.cpp
#include "B.h"
#include "Imp.h"
B::B(){ }
~B::B(){ }
Run Code Online (Sandbox Code Playgroud)
Imp.h
class Imp{};
Run Code Online (Sandbox Code Playgroud)
Main.cpp (编译我)
#include "B.h"
Run Code Online (Sandbox Code Playgroud)
错误:删除指向不完整类型的指针
错误:使用未定义类型'Imp'C2027
我可以以某种方式理解析构函数必须被移动到.cpp
,因为Imp
可能会被称为析构: -
delete pointer-of-Imp; //something like this
Run Code Online (Sandbox Code Playgroud)
但是,我不明白为什么规则也涵盖了构造函数(问题).
我读过了 :-
.cpp
.我有
template<typename T>
class queue
{
private:
struct node
{
T data;
std::unique_ptr<node> next; //compile error on incomplete type
node(T&& data_):
data(std::move(data_))
{}
};
std::unique_ptr<node> head;
node* tail;
public:
queue():
tail(nullptr)
{}
Run Code Online (Sandbox Code Playgroud)
我在 VS10 的标记行上收到编译错误。在这种情况下,我不应该被允许使用不完整的类型(实例化模板 - 构造函数 - 这里以 int 为例)?有解决办法吗?
编辑
singlethreadedqueue.h(62): error C2079: 'queue<T>::node::next' uses undefined class 'std::unique_ptr<_Ty>'
1> with
1> [
1> T=MyClass
1> ]
1> and
1> [
1> _Ty=queue<MyClass>::node
1> ]
1> c:\program files\microsoft visual studio 10.0\vc\include\memory(2161) : see reference to class template instantiation 'queue<T>::node' …
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用不使用命名空间的第三方C++库,并导致符号冲突.冲突的符号用于我的代码没有使用的类,所以我考虑为第三方库创建自定义头文件,其中类声明仅包括我的代码使用的公共成员,而忽略使用冲突类的任何成员.基本上创建一个界面.
我有三个问题:
如果.obj文件的编译工作,当我进行链接时,这种技术是否会导致符号冲突?
如果这不是问题,那么变化的类声明会在链接时引起问题吗?例如,链接器是否验证每个.obj文件使用的类的声明是否具有相同数量的成员?
如果这些都不是问题而且我能够链接.obj文件,它会在调用方法时引起问题吗?我不确切知道C++是如何工作的,但如果它使用索引指向类方法,并且那些索引从一个.obj文件到另一个不同,我猜这种方法会在运行时爆炸.
std::unique<B>
我为incomplete type创建了一个小测试用例B
。
测试.h
#pragma once
#include <memory>
class B; //<--- compile error here
class Test{
std::unique_ptr<B> bPtr;
//#1 need to move destructor's implementation to .cpp
public: ~Test();
};
Run Code Online (Sandbox Code Playgroud)
测试.cpp
#include "Test.h"
class B{};
Test::~Test(){} //move here because it need complete type of B
Run Code Online (Sandbox Code Playgroud)
主程序
#include <iostream>
#include "Test.h"
using namespace std;
int main(){
Test test;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我收到此错误:-
/usr/include/c++/4.8.2/bits/unique_ptr.h:65:22:错误:“sizeof”对不完整类型“B”的无效应用
据我了解,编译器告诉我这 B
是一个不完整的类型(in main.cpp
),因此它无法B
正确删除。
但是,在我的设计中,我不想main.cpp
拥有完整的B
.
粗略地说,这是一个粉刺。
有没有好的解决方法?
这里有一些类似的问题,但没有一个提出干净的解决方法。 …
假设我有一个公共类和一个私有实现类(例如PIMPL模式),我希望用一个带有checked delete的模板智能指针类来包装私有类,如下所示:
PublicClass.h
class PrivateClass;
// simple smart pointer with checked delete
template<class X> class demo_ptr
{
public:
demo_ptr (X* p) : the_p(p) { }
~demo_ptr () {
// from boost::checked_delete: don't allow compilation of incomplete type
typedef char type_must_be_complete[ sizeof(X)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete the_p;
}
private:
X* the_p;
};
// public-facing class that wishes to wrap some private implementation guts
class PublicClass
{
public:
PublicClass();
~PublicClass();
private:
demo_ptr<PrivateClass> pvt;
};
Run Code Online (Sandbox Code Playgroud)
PublicClass.cpp
#include "PublicClass.h"
class PrivateClass
{ …
Run Code Online (Sandbox Code Playgroud) 我为证明问题所需的大量代码道歉.我在使用带有std :: unique_ptr的pimpl习惯用法时遇到了问题.具体地说,当一个类(具有pimpl'ed实现)被用作具有pimpl'ed实现的另一个复合类中的成员数据时,似乎会出现问题.
我能够找到的大部分答案都是缺少明确的析构函数声明,但正如你在这里看到的,我已经声明并定义了析构函数.
这段代码有什么问题,可以修改它来编译而不改变设计吗?
注意:错误似乎发生在SomeComposite :: getValue()的定义中,并且编译器在编译时才能看到错误.在memory.h中遇到错误,消息是'sizeof'的无效应用程序到不完整类型'pimplproblem :: SomeInt :: impl'.
SomeInt.h
#pragma once
#include <iostream>
#include <memory>
namespace pimplproblem
{
class SomeInt
{
public:
explicit SomeInt( int value );
SomeInt( const SomeInt& other ); // copy
SomeInt( SomeInt&& other ) = default; // move
virtual ~SomeInt();
SomeInt& operator=( const SomeInt& other ); // assign
SomeInt& operator=( SomeInt&& other ) = default; // move assign
int getValue() const;
private:
class impl;
std::unique_ptr<impl> myImpl;
};
} …
Run Code Online (Sandbox Code Playgroud) 这不是std :: unique_ptr的欺骗,不完整的类型将无法编译.
请考虑以下代码:
#include <memory>
struct X
{
X();
~X();
struct Impl;
std::unique_ptr<Impl> up_;
};
struct Impl {}; // fully visible here
X::X() : up_{nullptr}{}
X::~X() = default;
int main()
{
X x;
}
Run Code Online (Sandbox Code Playgroud)
gcc/clang都吐出错误说不Impl
完整.但是,我提供了一个默认的析构函数,X
后面 Impl
是完全可见的,所以IMO代码应该编译.为什么不呢?现在出人意料:如果我做Impl
了一个内部类,即定义
struct X::Impl{};
Run Code Online (Sandbox Code Playgroud)
我正在使用 pimpl idiom 和 unique_ptr 编写一些代码。当我尝试使用类内初始化将 unique_ptr 默认设置为 nullptr 时,gcc 给出了编译错误,而 clang 和 msvc 都成功编译了代码。如果我没有使用类内初始化,错误就会消失。
\n\n// A.h\n#pragma once\n\n#include <memory>\n\nusing namespace std;\n\nclass B;\nclass A\n{\nprivate:\n ////////////////////////\n // here gives the error!\n ////////////////////////\n unique_ptr<B> impl{nullptr}; // error only with gcc, \n // ok with clang and msvc\n unique_ptr<B> impl2; // ok with all three\n\npublic:\n A();\n ~A();\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n// A.cpp\n#include "A.h"\n\nclass B\n{\nprivate:\n int b{5};\n\npublic:\n B() = default;\n ~B() = default;\n};\n\nA::A() = default;\nA::~A() = default;\n
Run Code Online (Sandbox Code Playgroud)\n\n// main.cpp\n#include "A.h"\n\nint main()\n{\n A a;\n return 0;\n}\n …
Run Code Online (Sandbox Code Playgroud) c++ ×13
c++11 ×8
unique-ptr ×7
pimpl-idiom ×6
c++14 ×1
c++17 ×1
c++builder ×1
class ×1
compilation ×1
declaration ×1
destructor ×1
gcc8 ×1
stl ×1
templates ×1
windows ×1