gpt4 book ai didi

c++ - move ctor和 move dtor

转载 作者:行者123 更新时间:2023-11-30 04:38:02 27 4
gpt4 key购买 nike

正如我在Move constructor/operator=中询问的那样,过了一段时间,我同意并接受了这个问题的正确答案,我只是在想,是否有类似“移动析构函数” 这样的东西会在每次移动的对象上调用会有用吗?我们使用了move ctor或operator =。
这样,我们仅需在move dtor中指定要从中获得什么,以及在被move构造函数使用后如何使对象无效。没有这种语义,似乎每次我编写move ctor或operator =时,我都必须在它们中明确声明(代码重复/错误引入)如何使移动的对象无效,这不是我认为的最佳选择。期待您对这个问题的看法。

最佳答案

您能否举一个具体的例子,在哪里有用。例如,据我所知,一般情况下,移动分配可以实现为

this->swap(rhv); 

如果该类从移动语义中受益,那么swap方法在任何情况下都可能是有益的。这很好地将释放 *this的旧资源的工作委托(delegate)给常规析构函数。

如果没有显示新的析构函数的特定示例是实现正确代码的一种优雅方法,您的建议看起来就不会很吸引人。

另外,根据最新版本,可以默认移动构造函数/赋值运算符。这意味着很有可能
我的类(class)将如下所示:
class X
{
well_behaved_raii_objects;
public:
X(X&& ) = default;
X& operator=(X&&) = default;
};

根本没有破坏者!是什么让我拥有两个析构函数吸引我的呢?

还应考虑到赋值运算符有旧资源要处理。根据当前标准,您必须注意,在构造和赋值后,正常的析构函数调用都可以,并且IMO与拟议的移动析构函数类似,您必须在构造函数和赋值运算符中注意,可以使用相同的移动析构函数安全地调用。还是您想要两个销毁破坏器-每个销毁一个? :)

使用move构造器/赋值的注释中的 msdn example的重做示例
#include <algorithm>

class MemoryBlock
{
public:

// Simple constructor that initializes the resource.
explicit MemoryBlock(size_t length)
: length(length)
, data(new int[length])
{
}

// Destructor.
~MemoryBlock()
{
delete[] data; //checking for NULL is NOT necessary
}

// Copy constructor.
MemoryBlock(const MemoryBlock& other)
: length(other.length)
, data(new int[other.length])
{
std::copy(other.data, other.data + length, data);
}

// Copy assignment operator (replaced with copy and swap idiom)
MemoryBlock& operator=(MemoryBlock other) //1. copy resource
{
swap(other); //2. swap internals with the copy
return *this; //3. the copy's destructor releases our old resources
}

//Move constructor
//NB! C++0x also allows delegating constructors
//alternative implementation:
//delegate initialization to default constructor (if we had one), then swap with argument
MemoryBlock(MemoryBlock&& other)
: length(other.length)
, data(other.data)
{
other.data = 0; //now other can be safely destroyed
other.length = 0; //not really necessary, but let's be nice
}

MemoryBlock& operator=(MemoryBlock&& rhv)
{
swap(rhv);
//rhv now contains previous contents of *this, but we don't care:
//move assignment is supposed to "ruin" the right hand value anyway
//it doesn't matter how it is "ruined", as long as it is in a valid state
//not sure if self-assignment can happen here: if it turns out to be possible
//a check might be necessary, or a different idiom (move-and-swap?!)
return *this;
}


// Retrieves the length of the data resource.
size_t Length() const
{
return length;
}

//added swap method (used for assignment, but recommended for such classes anyway)
void swap(MemoryBlock& other) throw () //swapping a pointer and an int doesn't fail
{
std::swap(data, other.data);
std::swap(length, other.length);
}

private:
size_t length; // The length of the resource.
int* data; // The resource.
};

对原始MSDN示例的一些评论:

1)不需要在 delete之前检查NULL(也许对我剥离的输出在这里完成,也许表明是误解)

2)删除赋值运算符中的资源:代码重复。使用 copy-and-swap 惯用法删除以前保留的资源时,会将其委派给析构函数。

3) copy-and-swap 的习惯用法也使自我分配检查变得不必要。如果在删除资源之前先将其复制,这不是问题。 -(另一方面,“无论如何复制资源”只会在您期望与此类进行大量的自我分配时才受到伤害。)

4)在MSDN的示例中,赋值运算符缺乏任何类型的异常安全性:如果分配新存储失败,则该类将处于无效状态,且指针无效。销毁后将发生不确定的行为。

可以通过仔细地重新排列语句的顺序,并将删除的指针设置为NULL来改善这一点(不幸的是,该特定类的不变性似乎是它始终持有资源,因此,在出现错误的情况下让它干净地丢失资源)异常也不完美)。相比之下,使用 copy-and-swap 时,如果发生异常,则左侧值将保持其原始状态(更好的是,操作无法完成,但可以避免数据丢失)。

5)自赋值检查在移动赋值运算符中看起来特别有问题。我不知道左手值与右手值如何相同。是否需要 a = std::move(a);来实现身份(无论如何看起来都是未定义的行为?)?

6)同样,移动分配不必要地管理资源,而我的版本只是简单地将其委托(delegate)给常规析构函数。

结论:您看到的代码重复是可以避免的,它只是由一个幼稚的实现引入的(出于某种原因,您倾向于在教程中看到它,这可能是因为带有重复的代码对于学习者来说更容易理解)。

To prevent resource leaks, always free resources (such as memory, file handles, and sockets) in the move assignment operator.



...如果代码重复对您来说很好,否则请重用析构函数。

To prevent the unrecoverable destruction of resources, properly handle self-assignment in the move assignment operator.



...或者确保在可以更换之前,不要删除任何东西。
或更确切地说,是一个SO问题:如果在定义明确的程序中进行移动分配,是否可能发生自我分配。

此外,从我的草案(3092)中,我发现如果一个类没有用户定义的副本构造函数/赋值运算符,并且没有任何东西阻止移动构造函数/赋值的存在,则将隐式声明其为默认值。如果我没记错的话,这意味着:如果成员是字符串, vector ,shared_ptrs等,在这种情况下,您通常不会编写副本构造函数/赋值,则可以免费获得move构造函数/ move赋值。

关于c++ - move ctor和 move dtor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3398761/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com