我第一次尝试使用C++ 11 unique_ptr; 我正在替换我的一个项目中的多态原始指针,该指针由一个类拥有,但经常传递.
我以前的功能如下:
bool func(BaseClass* ptr, int other_arg) {
bool val;
// plain ordinary function that does something...
return val;
}
Run Code Online (Sandbox Code Playgroud)
但我很快意识到我无法切换到:
bool func(std::unique_ptr<BaseClass> ptr, int other_arg);
Run Code Online (Sandbox Code Playgroud)
因为调用者必须处理函数的指针所有权,所以我不想这样做.那么,什么是我的问题的最佳解决方案?
我虽然将指针作为参考传递,如下所示:
bool func(const std::unique_ptr<BaseClass>& ptr, int other_arg);
Run Code Online (Sandbox Code Playgroud)
但是我觉得这样做非常不舒服,首先是因为传递已经输入的内容似乎并非本能,_ptr作为参考的参考.其次,因为功能签名变得更大.第三,因为在生成的代码中,需要两个连续的指针间接来达到我的变量.
为unique_ptr保证存储nullptr移动之后?
std::unique_ptr<int> p1{new int{23}};
std::unique_ptr<int> p2{std::move(p1)};
assert(!p1); // is this always true?
Run Code Online (Sandbox Code Playgroud) 双方unique_ptr并shared_ptr接受定制的析构函数他们所拥有的对象上调用.但在的情况下unique_ptr,析构函数作为一个模板参数传递类,而类型shared_ptr的自定义析构函数将被指定为一个模板参数的构造函数.
template <class T, class D = default_delete<T>>
class unique_ptr
{
unique_ptr(T*, D&); //simplified
...
};
Run Code Online (Sandbox Code Playgroud)
和
template<class T>
class shared_ptr
{
template<typename D>
shared_ptr(T*, D); //simplified
...
};
Run Code Online (Sandbox Code Playgroud)
我不明白为什么会有这样的差异.需要什么?
我怎样才能将std::unique_ptr函数传递给函数?可以说我有以下课程:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
Run Code Online (Sandbox Code Playgroud)
以下内容无法编译:
void MyFunc(unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么我不能传入std::unique_ptr函数?当然这是构造的主要目的吗?或者C++委员会是否打算让我回到原始的C风格指针并将其传递给它:
MyFunc(&(*ptr));
Run Code Online (Sandbox Code Playgroud)
最奇怪的是,为什么这是一种传递它的好方法?看起来非常不一致:
MyFunc(unique_ptr<A>(new A(1234)));
Run Code Online (Sandbox Code Playgroud) 我发现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)中定义的.
鉴于自有对象的生命周期与其所有者链接的常见情况,我可以使用两种方式之一的唯一指针..
它可以分配:
class owner
{
std::unique_ptr<someObject> owned;
public:
owner()
{
owned=std::unique_ptr<someObject>(new someObject());
}
};
Run Code Online (Sandbox Code Playgroud)
可以使用重置方法:
class owner
{
std::unique_ptr<someObject> owned;
public:
owner()
{
owned.reset(new someObject());
}
};
Run Code Online (Sandbox Code Playgroud)
为了最佳实践,我应该更喜欢一种形式吗?
编辑:对不起伙计们.我简化了这个.堆分配发生在初始化方法中,而不是在ctor中.因此,我无法使用初始化列表.
这是我在尝试将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) 我试图unique_ptr在一个unique_ptr带有基类的函数中使用一个派生类.就像是:
class Base {};
class Derived : public Base {};
void f(unique_ptr<Base> const &base) {}
…
unique_ptr<Derived> derived = unique_ptr<Derived>(new Derived);
f(derived);
Run Code Online (Sandbox Code Playgroud)
如果我正确理解了这个答案,那么这段代码应该可行,但它会导致以下编译错误:
错误C2664:'f':无法将参数1从'std :: unique_ptr <_Ty>'转换为'const std :: unique_ptr <_Ty>&'
IntelliSense:没有合适的用户定义转换,从"std :: unique_ptr <Derived,std :: default_delete <Derived >>"到"const std :: unique_ptr <Base,std :: default_delete <Base >>"存在
如果我改变f采取unique_ptr<Derived> const &derived,它工作正常,但这不是我想要的.
难道我做错了什么?我该怎么做才能解决这个问题?
我正在使用Visual Studio 2012.
我有一系列工厂回归unique_ptr<Base>.引擎盖下,虽然,他们所提供的指针各种衍生类型,即unique_ptr<Derived>,unique_ptr<DerivedA>,unique_ptr<DerivedB>等
鉴于DerivedA : Derived并且Derived : Base我们有:
unique_ptr<Base> DerivedAFactory() {
return unique_ptr<Base>(new DerivedA);
}
Run Code Online (Sandbox Code Playgroud)
我需要做的是将指针从返回"转换" unique_ptr<Base>到某个派生级别(不一定是原始的内部级别).用伪代码说明:
unique_ptr<Derived> ptr = static_cast<unique_ptr<Derived>>(DerivedAFactory());
Run Code Online (Sandbox Code Playgroud)
我正在考虑通过从中释放对象unique_ptr,然后使用一个转换原始指针的函数并将其重新分配给另一个unique_ptr所需的风格(release在调用之前由调用者显式完成)来实现这一点:
unique_ptr<Derived> CastToDerived(Base* obj) {
return unique_ptr<Derived>(static_cast<Derived*>(obj));
}
Run Code Online (Sandbox Code Playgroud)
这是有效的,还是/会有什么时髦吗?
PS.还有一个复杂的问题是,有些工厂驻留在运行时动态加载的DLL中,这意味着我需要确保生成的对象在创建它们的同一个上下文(堆空间)中被销毁.所有权的转移(通常发生在另一个上下文中)必须从原始上下文中提供删除.但除了必须与指针一起提供/转换删除器之外,铸造问题应该是相同的.
在boost库中是否有一些与C++ 1x的std :: unique_ptr等效的类?我正在寻找的行为是能够拥有异常安全的工厂功能,就像这样......
std::unique_ptr<Base> create_base()
{
return std::unique_ptr<Base>(new Derived);
}
void some_other_function()
{
std::unique_ptr<Base> b = create_base();
// Do some stuff with b that may or may not throw an exception...
// Now b is destructed automagically.
}
Run Code Online (Sandbox Code Playgroud)
编辑:现在,我正在使用这个黑客,这似乎是我能在这一点上得到的最好的......
Base* create_base()
{
return new Derived;
}
void some_other_function()
{
boost::scoped_ptr<Base> b = create_base();
// Do some stuff with b that may or may not throw an exception...
// Now b is deleted automagically.
}
Run Code Online (Sandbox Code Playgroud)