回到我疯狂的AutoArray thingy ...(引用那里的重要部分:
class AutoArray
{
void * buffer;
public:
//Creates a new empty AutoArray
AutoArray();
//std::auto_ptr copy semantics
AutoArray(AutoArray&); //Note it can't be const because the "other" reference
//is null'd on copy...
AutoArray& operator=(AutoArray);
~AutoArray();
//Nothrow swap
// Note: At the moment this method is not thread safe.
void Swap(AutoArray&);
};
)
无论如何,试图实现复制构造函数。有一段客户端代码(尚未提交到bitbucket,因为它不会构建)看起来像这样:
AutoArray NtQuerySystemInformation(...) { ... };
AutoArray systemInfoBuffer = NtQuerySystemInformation(...);
这会失败,因为复制构造函数将非const
引用作为参数....但我不知道如何修改复制构造函数以获取const
引用,给定指派中使用的来源AutoArray
已被修改(因此不会是const
)。当然,你无法修改要使用的值,因为它是复制构造函数,并且它是一个无限循环!
如果我使用auto_ptr
,这将是有效的:
std::auto_ptr NtQuerySystemInformation(...) { ... };
std::auto_ptr systemInfoBuffer = NtQuerySystemInformation(...);
那么,如果一个具有auto_ptr
复制语义的类可以吗?
答案 0 :(得分:14)
auto_ptr
使用了一个肮脏的技巧。
我将使用名为auto_int
的简化类来演示复制构造功能,而不会带来模板或继承引入的任何复杂性。我认为代码大多是正确的,但它没有经过测试。我们的基本auto_int
看起来像这样:
class auto_int
{
public:
auto_int(int* p = 0) : p_(p) { }
~auto_int() { delete p_; }
// copy constructor taking a non-const reference:
auto_int(auto_int& other)
: p_(other.release()) { }
int* release()
{
int* temp = p_;
p_ = 0;
return temp;
}
private:
int* p_;
};
使用此基本auto_int
,我们无法复制临时对象。我们的目标是能够写出如下内容:
auto_int p(auto_int(new int()));
我们可以做的是使用助手类。对于auto_ptr
,这称为auto_ptr_ref
。我们会致电我们auto_int_ref
:
class auto_int;
class auto_int_ref
{
public:
auto_int_ref(auto_int* p) : p_(p) { }
auto_int& ref() { return *p_; }
private:
auto_int* p_;
};
基本上,这个类的一个实例只存储一个指向auto_int
的指针,并允许我们将它用作"引用"到auto_int
。
然后在我们的auto_int
课程中,我们需要两个额外的功能。我们需要另一个带auto_int_ref
的构造函数,我们需要一个转换运算符,允许auto_int
隐式转换为auto_int_ref
:
auto_int(auto_int_ref other)
: p_(other.ref().release()) { }
operator auto_int_ref() { return this; }
这将使我们能够复制"一个临时的,但仍然有复制构造函数采取非const引用。如果我们再看一下示例代码:
auto_int p(auto_int(new int()));
我们会构建一个新的临时auto_int
并将new int()
传递给采用int*
的构造函数。然后,使用auto_int_ref
将此临时转换为指向它的operator auto_int_ref()
,使用auto_int
的{{1}}构造函数初始化auto_int_ref
答案 1 :(得分:3)
auto_ptr
的副本ctor通过从传入的对象中取消所有权来工作。这也是auto_ptr
无法在vector
或其他STL集合中使用的重要原因。
这不是大多数复制构造函数的工作方式。通常,您的复制构造函数将只克隆传入的对象,因此您可以将const引用传递给它。但是auto_ptr
并没有这样做。它实际上修改了原始对象。从这个意义上说,它只是一个名称的复制构造函数,而不是语义。
我正试着把它煮沸一点。因此,你有效地尝试对你的类做一些允许语法类似的事情:
#include <string>
#include <memory>
using namespace std;
auto_ptr<string> gimme()
{
return auto_ptr<string>(new string("Hello"));
}
int main()
{
auto_ptr<string> s = gimme();
}
...而且您想知道如何让s = gimme()
部分发挥作用。正确?
这里的秘密在于代理类,auto_ptr_ref
由标准在20.4.5中描述,其目的是“允许auto_ptr对象传递给函数并从函数返回。”:
namespace std {
template <class Y> struct auto_ptr_ref {};
template<class X> class auto_ptr {
public:
typedef X element_type;
// 20.4.5.1 construct/copy/destroy:
explicit auto_ptr(X* p =0) throw();
auto_ptr(auto_ptr&) throw();
template<class Y> auto_ptr(auto_ptr<Y>&) throw();
auto_ptr& operator=(auto_ptr&) throw();
template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();
auto_ptr& operator=(auto_ptr_ref<X> r) throw();
˜auto_ptr() throw();
// 20.4.5.2 members:
X& operator*() const throw();
X* operator->() const throw();
X* get() const throw();
X* release() throw();
void reset(X* p =0) throw();
// 20.4.5.3 conversions:
auto_ptr(auto_ptr_ref<X>) throw();
template<class Y> operator auto_ptr_ref<Y>() throw();
template<class Y> operator auto_ptr<Y>() throw();
};
}
答案 2 :(得分:0)
没有从T*
到std::auto_ptr<T>
的隐式转换。我猜你确实有一个从NTSTATUS
句柄到AutoArray
的隐式转换构造函数。但是如果该转换创建了一个临时的,那么临时就无法复制。
如果您使用直接初始化而不是复制初始化,则您的“问题”可能会消失。
AutoArray systemInfoBuffer( ntDll.NtQuerySystemInformation(
Dll::NtDll::SystemProcessInformation) );