将资源移出泛型类

Moving resources out of a generic class

本文关键字:泛型类 移出 资源      更新时间:2023-10-16

在上下文中如下:

template <class T>
struct MyStruct
{
    T resource; 
    decltype(auto) getResource()
    {
        return std::move(resource); 
    }     
};

我的getResource方法是否在做我希望它做的事情,即将resource成员移出类?我想在不再使用MyStruct并且可以从中"窃取"内存的情况下使用它。

template <class T>
struct MyStruct
{
    T resource; 
    decltype(auto) getResource()
    {
        return std::move(resource); 
    }
};

decltype(auto)T&&的,但T&&本身不会窃取资源(但允许它被隐式窃取)。

另一种选择是

template <class T>
struct MyStruct
{
    T resource; 
    T takeResource()
    {
        return std::move(resource); 
    }
};

在这里,一旦调用takeResource,资源就已转移。

所以例如

MyStruct<std::unique_ptr<int>> foo; foo.resource = std::make_unique<int>(42);
*foo.get_resource() = 51; // No transfer ownership, just get a reference
*foo.get_resource() = 69; // still works.

*foo.get_resource() = 51; // Transfer ownership, and resource will be released here
*foo.get_resource() = 69; // dereferencing nullptr -> UB.

这完全取决于T是什么以及它的移动构造函数是如何编写的。例如,如果它是一个int,它只是复制它。如果是std::unique_ptr,它将完全按照您的期望进行操作。

为了更好地理解,请参阅此示例:

#include <iostream>
#include <string>
class copyable{
public:
    copyable():x(0){};
    ~copyable()=default;
    copyable(copyable const&)=default;
    copyable(copyable&&)=default;
    int x;
};
class moveable{
public:
    moveable():x(new int{0}){};
    ~moveable(){
        delete[] x;
    };
    moveable(moveable const&)=delete;
    moveable(moveable&& other){
        this->x=other.x;
        other.x=nullptr;
    };
    int* x;
};
template <class T>
struct MyStruct
{
    T resource; 
    decltype(auto) getResource()
    {
        return std::move(resource); 
    }     
};
int main()
{
    MyStruct<copyable> a;
    std::cout << a.resource.x <<"n";
    MyStruct<moveable> b; 
    std::cout << "address: "<< b.resource.x << "tval: " << *b.resource.x <<"nn";
    auto temp_a=a.getResource();
    std::cout << temp_a.x <<"n";
    auto temp_b=b.getResource();
    std::cout << "address: "<< temp_b.x << "tval: " << *temp_b.x <<"nn";

    std::cout << a.resource.x <<"n";
    std::cout << "address: "<< b.resource.x << "tval: " << /* *b.resource.x <<  THIS IS UB */ "nn";
}

输出:

0
address: 0x2d366f0    val: 0
0
address: 0x2d366f0    val: 0
0
address: 0    val:

现场演示

std::move不会

自行移动,这是一个轻微的误称。 std::move here只能确保右值。您的 T 型还需要有一个构造函数来允许实际移动它。

总而言之,您无法确保您的资源不会被复制。

如果要明确谁在特定时间拥有唯一资源,请传递唯一指针。 唯一指针是通用的,如果您优化设计足够长的时间,则可能是您最终实现的东西。