如何实现std :: auto_ptr的复制构造函数? [英] How could one implement std::auto_ptr's copy constructor?

查看:117
本文介绍了如何实现std :: auto_ptr的复制构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

回到我疯狂的 AutoArray thingy ...(引用重要的位:

  class AutoArray 
{
void * buffer;
public :
//创建一个新的空AutoArray
AutoArray();
// std :: auto_ptr复制语义
AutoArray(AutoArray&); //注意它不能const
AutoArray& operator =(AutoArray);
〜AutoArray();
// Nothrow swap
//注意:此时此方法不是线程安全的
void Swap(AutoArray&);
};



无论如何,试图实现复制构造函数。有一个客户端代码(尚未提交到bitbucket,因为它不会构建),如下所示:

  AutoArray NtQuerySystemInformation (...){...}; 

AutoArray systemInfoBuffer = NtQuerySystemInformation(...);

这会失败,因为复制构造函数采用非 - const 引用作为参数....但我不知道如何修改复制构造函数以获取 const 引用,假定源 AutoArray 在修改中使用(因此不会是 const )。你不能修改东西来使用pass by value当然,因为它是复制构造函数,并且将是一个无限循环!



如果我使用 auto_ptr ,这将有效:

  std :: auto_ptr NtQuerySystemInformation ){...}; 

std :: auto_ptr systemInfoBuffer = NtQuerySystemInformation(...);

那么, auto_ptr 复制语义是否可能?

解决方案

auto_ptr



我将使用一个名为 auto_int 的简单类来演示由模板或继承引入的任何复杂性。我认为代码大多是正确的,但它是未经测试。我们的基本 auto_int 看起来像这样:

  class auto_int 
{
public:

auto_int(int * p = 0):p_(p){}

〜auto_int(){delete p_; }

//复制构造函数接受非const引用:
auto_int(auto_int& other)
:p_(other.release()){}

int * release()
{
int * temp = p_;
p_ = 0;
return temp;
}

private:

int * p_;
};

使用这个基本的 auto_int t复制临时对象。我们的目标是能够写如下:

  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()){}

运算符auto_int_ref(){return this; }

这将允许我们复制一个临时文件, const引用。如果我们再看看我们的示例代码:

  auto_int p(auto_int(new int())); 

我们构造一个新的临时 auto_int 并将 int * 传递给构造函数 new int()。然后,使用运算符auto_int_ref()将该临时变量转换为指向它的 auto_int_ref c $ c> auto_int 构造函数使用 auto_int_ref 初始化 p 。 / p>

Back on my crazy AutoArray thingy... (quoting important bits from there:

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&);
};

)

Anyway, trying to implement the copy constructor. There's a piece of client code (not yet committed into bitbucket because it won't build) that looks like this:

AutoArray NtQuerySystemInformation(...) { ... };

AutoArray systemInfoBuffer = NtQuerySystemInformation(...);

This fails because the copy constructor takes a non-const reference as an argument .... but I don't see how you could modify the copy constructor to take a const reference, given that the source AutoArray used in the assignment is modified (and therefore wouldn't be const). You can't modify things to use pass by value of course, because it's the copy constructor and that'd be an infinite loop!

If I was using auto_ptr, this would be valid:

std::auto_ptr NtQuerySystemInformation(...) { ... };

std::auto_ptr systemInfoBuffer = NtQuerySystemInformation(...);

How then, can a class with auto_ptr's copy semantics be possible?

解决方案

auto_ptr uses a dirty trick.

I'll use a dumbed-down class named auto_int to demonstrate just the copy construction functionality without bringing in any complexities introduced by templates or inheritance. I think the code is mostly correct, but it's untested. Our basic auto_int look something like this:

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_;
};

With this basic auto_int, we can't copy a temporary object. Our goal is to be able to write something like:

auto_int p(auto_int(new int()));

What we can do is use a helper class. For auto_ptr, this is called auto_ptr_ref. We'll call ours 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_;
};

Basically, an instance of this class just stores a pointer to an auto_int and allows us to use it as a "reference" to an auto_int.

Then in our auto_int class we need two additional functions. We need another constructor that takes an auto_int_ref and we need a conversion operator that allows an auto_int to be implicitly converted to an auto_int_ref:

auto_int(auto_int_ref other)
    : p_(other.ref().release()) { }

operator auto_int_ref() { return this; }

This will allow us to "copy" a temporary while still having the copy constructor take a non-const reference. If we look again at our sample code:

auto_int p(auto_int(new int()));

What happens is we construct a new temporary auto_int and pass new int() to the constructor that takes an int*. This temporary is then converted to an auto_int_ref that points to it, using the operator auto_int_ref(), and the auto_int constructor that takes an auto_int_ref is used to initialize p.

这篇关于如何实现std :: auto_ptr的复制构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆