我正在寻找允许在另一个类的头文件中进行类的前向声明的定义:
我是否允许为基类,作为成员持有的类,通过引用传递给成员函数的类等执行此操作?
我正在使用pimpl-idiom std::unique_ptr:
class window {
window(const rectangle& rect);
private:
class window_impl; // defined elsewhere
std::unique_ptr<window_impl> impl_; // won't compile
};
Run Code Online (Sandbox Code Playgroud)
但是,我在第304行的第304行收到有关使用不完整类型的编译错误<memory>:
'
sizeof'到不完整类型'uixx::window::window_impl的应用无效' '
据我所知,std::unique_ptr应该可以使用不完整的类型.这是libc ++中的错误还是我在这里做错了什么?
我发现std::unique_ptr在下面的代码中结合使用前向声明类很有用.它编译并与GCC一起工作,但整个事情似乎有点奇怪,我想知道这是否是标准行为(即标准要求)?因为B声明时B不是完整的类型unique_ptr.
#include <memory>
class B;
class A {
std::unique_ptr<B> myptr;
// B::~B() can't be seen from here
public:
~A();
};
Run Code Online (Sandbox Code Playgroud)
#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.
Run Code Online (Sandbox Code Playgroud)
我怀疑这与析构函数有关(因此需要调用析构函数unique_ptr<B>)是在特定的编译单元(A.cpp)中定义的.
这是我在尝试将unique_ptr用于pimpl时所看到的简化.我选择了unique_ptr,因为我真的希望类拥有指针 - 我希望pimpl指针和类的生命周期相同.
无论如何,这是标题:
#ifndef HELP
#define HELP 1
#include <memory>
class Help
{
public:
Help(int ii);
~Help() = default;
private:
class Impl;
std::unique_ptr<Impl> _M_impl;
};
#endif // HELP
Run Code Online (Sandbox Code Playgroud)
这是来源:
#include "Help.h"
class Help::Impl
{
public:
Impl(int ii)
: _M_i{ii}
{ }
private:
int _M_i;
};
Help::Help(int ii)
: _M_impl{new Help::Impl{ii}}
{ }
Run Code Online (Sandbox Code Playgroud)
我可以将它们编译成一个库就好了.但是当我尝试在测试程序中使用它时,我得到了
ed@bad-horse:~/ext_distribution$ ../bin/bin/g++ -std=c++0x -o test_help test_help.cpp Help.cpp
In file included from /home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/memory:86:0,
from Help.h:4,
from test_help.cpp:3:
/home/ed/bin/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = …Run Code Online (Sandbox Code Playgroud) 我一直在使用pimpl成语制作一些对象,但我不确定是否使用std::shared_ptr或std::unique_ptr.
据我所知,std::unique_ptr是更有效的,但是这是没有这么多的问题,对我来说,因为这些物体是比较重量级反正做的成本std::shared_ptr比std::unique_ptr相对较小.
我目前std::shared_ptr只是因为额外的灵活性.例如,使用a std::shared_ptr允许我将这些对象存储在散列映射中以便快速访问,同时仍然能够将这些对象的副本返回给调用者(因为我相信任何迭代器或引用可能很快变得无效).
但是,这些对象确实没有被复制,因为更改会影响所有副本,所以我想知道也许使用std::shared_ptr和允许副本是某种反模式或坏事.
它是否正确?
为什么make_unique调用编译?make_unqiue不要求其模板参数是完整类型吗?
struct F;
int main()
{
std::make_unique<F>();
}
struct F {};
Run Code Online (Sandbox Code Playgroud)
在从orignated问题我的"问题"与我PIMPL实现:
我确实理解为什么析构函数必须在用户声明并在实现类(PIMPL)的cpp文件中定义.
但是移动包含pimpl的类的构造函数仍会编译.
class Object
{};
class CachedObjectFactory
{
public:
CachedObjectFactory();
~CachedObjectFactory();
std::shared_ptr<Object> create(int id) const;
private:
struct CacheImpl;
std::unique_ptr<CacheImpl> pImpl;
};
Run Code Online (Sandbox Code Playgroud)
现在cpp文件:
// constructor with make_unique on incompete type ?
CachedObjectFactory::CachedObjectFactory()
: pImpl(std::make_unique<CacheImpl>())
{}
struct CachedObjectFactory::CacheImpl
{
std::map<int, std::shared_ptr<Object>> idToObjects;
};
//deferred destructor
CachedObjectFactory::~CachedObjectFactory() = default;
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么这个编译?为什么建筑和破坏之间存在差异?如果析构函数的实例化和default_deleter的实例化是一个问题,为什么make_unique的实例化不是问题?
说我有两个班:
"foo.h中"
#pragma once
class Foo
{
public:
Foo()
{
};
~Foo()
{
};
};
Run Code Online (Sandbox Code Playgroud)
"啊"
#pragma once
#include <memory>
class Foo;
class A
{
public:
A(){};
~A(){};
std::unique_ptr<Foo> foo;
};
Run Code Online (Sandbox Code Playgroud)
A持有unique_ptr的Foo.我不想包含Foo在"啊"中,所以我向前宣布它.通过Foo在"Ah"中向前声明类,我得到一个编译时错误:
error C2027: use of undefined type 'Foo'
error C2338: can't delete an incomplete type
Run Code Online (Sandbox Code Playgroud)
所以我下面这个文章就如何避免这种错误,并在它自己的.cpp文件,我还包括富移动A的析构函数:
"A.cpp"
#include "A.h"
#include "Foo.h"
A::A()
{
}
A::~A()
{
}
Run Code Online (Sandbox Code Playgroud)
在"A.cpp"中实现A的析构函数后,我能够编译程序,因为类Foo在"A.cpp"中已知.这似乎是合乎逻辑的,因为unique_ptr需要完整的类型来调用它的析构函数.但令我惊讶的是,在评论出A的构造函数(在"Ah"以及"A.cpp"中)后,我得到了同样的错误.这怎么可能?为什么编译器抱怨在A没有构造函数时无法调用Foo的析构函数?
编辑:我上传了4个文件,以便您可以测试该程序.我正在使用Visual Studio 2013的MSVC++.
当我尝试以下操作时,GCC编译器会抱怨(见下文).class Face需要不完整,因为它包含指向class Element同样包含指针的指针class Face.换句话说,类之间存在循环依赖关系.我该如何解决?
错误:'sizeof'无效应用于不完整类型'Face'
class Face; // needs to be incomplete
class Element
{
std::vector < std::unique_ptr <Face> > face;
};
class Face
{
std::vector < std::unique_ptr <Element> > elm;
};
Run Code Online (Sandbox Code Playgroud) 我有两个标准容器.它们都指向相同的数据结构.第一个包含所有数据,第二个包含一些相同的数据.我应该使用shared_ptr或weak_ptr在第二个容器上?
首先,当我阅读我想unique_ptr在第一个集合上使用的参考时.我的第一个集合包含所有数据,它是唯一一个"拥有"的数据.这意味着如果数据不存在,则应将其删除.但是当我尝试创建第二个集合时,我不知道该怎么做.我创建了一个唯一的指针,但现在我需要另一个指向同一元素的指针来破坏唯一性,但事实上真正的所有者并不是新的指针.所以我理解(我希望我没有错),唯一性是在达到元素的方式而不是(例如)删除元素的可能性.所以,shared_ptr.我在他的第一个系列中有它们.但是现在第二个出现了,我想用了shared_ptr这里也.访问相同数据的方式可能都是,因此所有者是两个.但在我的情况下,数据总是从之前的第二个删除.如果我使用a weak_ptr,所有者的数量不会增加.在这两种情况下,当第一个集合需要时,元素将被删除.最后我正在使用shared_ptr因为weak_ptr我需要lock()每行代码中的每个指针,使其可读性降低.但我应该真正使用什么?
我正在上课STFT.在标题中编译就好了:
class STFT; // pimpl off to prevent point name clash
class Whatever
{
private:
STFT* stft;
Run Code Online (Sandbox Code Playgroud)
这在实施中:
#include "STFT.h"
Whatever::Whatever() : stft(new STFT()) {
// blah blah
}
Whatever::~Whatever() {
delete stft; // pure evil
}
Run Code Online (Sandbox Code Playgroud)
但是,切换到std::unique_ptr<STFT> stft;标题中的原始指针,并删除析构函数,我得到
错误:'sizeof'无效应用于不完整类型'STFT'static_assert(sizeof(_Tp)> 0,"default_delete无法删除不完整类型");
但是,如果我只提供一个空的析构函数Whatever::~Whatever(){},那么它编译得很好.这让我完全难过.请填写我这个毫无意义的析构函数为我做的事情.
c++ ×10
unique-ptr ×6
c++11 ×5
pimpl-idiom ×4
c++-faq ×1
containers ×1
destructor ×1
libc++ ×1
shared-ptr ×1
templates ×1