C++ 使用指针移动构造函数(*&&&语法)

C++ Move Constructor With Pointers (*&& Syntax)

本文关键字:语法 构造函数 指针 移动 C++      更新时间:2023-10-16

我想知道C++中的构造<type>*&&是否有任何问题。让我举一个具体的例子。

假设我们有一个类,它应该由数组构造而成。我们通常会这样做:

class Things 
{
public:
Things(const ThingType* arrayOfThings, int sizeOfArray) 
: myArray(new ThingType[sizeOfArray])
{
for (int i = 0; i < sizeOfArray; i++)
myArray[i] = arrayOfThings[i]; 
}
private:
ThingType* myArray;
}

如果我们想保留arrayOfThings,这很好,因为我们正在对其进行深度复制。此外,通过使用const,我们确保它不会在构造函数中被修改。

但假设我们的程序有很多这样的语句:

Things myThings(new ThingType[9001] {thing_0, ... , thing_9000}, 9001);

这可能看起来很奇怪,但可能会发生巨大的ThingType数组作为右值从函数返回的情况。

在这种情况下,我们不关心保留作为参数传递的指针。事实上,我们绝对不想对其进行深入复制,因为保存我们无论如何都要销毁的东西将是一种巨大的时间浪费。

一个可能的解决方案是添加另一个构造函数来处理非常量右值ThingType指针的情况,就像普通的move构造函数处理类的非常量右价实例的情况一样:

public:
Things(ThingType*&& arrayOfThings, int sizeOfArray) 
: myArray(arrayOfThings)
{
arrayOfThings = NULL;                  
}

这似乎解决了我的问题,但我没有发现上面看到的关于<type>*&&结构的太多信息。这是犹太洁食吗,还是我会因为混合指针和引用而被送到地下城?

经过一段时间后,我相信我找到了令人满意的解决方案,尽管远非最佳解决方案。由于没有人回答这个问题,我将分享我找到的最佳解决方案。

正如Justin所指出的,当我们在构造函数调用中获取ThingType变量的地址(而不是ThingType指针的地址,正如他在回答中所暗示的那样)时,使用ThingType*&&可能会带来麻烦。

如果tThingType,则表达式&t是类型为ThingType*的r值,因此Thing myThing(&t, ...)将调用move构造函数,结果使myThing.myArray指向t。在大多数情况下,这不是我们想要的。

一种解决方案是使用矢量而不是阵列,如下所示:

// Copy
explicit Things(const std::vector<ThingType>& vectorOfThings) 
: myVector(vectorOfThings)
{  }
// Move
explicit Things(std::vector<ThingType>&& vectorOfThings) 
: myVector(std::move(vectorOfThings))
{  }

move构造函数将用于以下情况:

Things myThings(vector<ThingType>{thing_0, ... , thing_9000});

虽然这解决了问题,但如果我们依赖于返回原始指针的API,或者如果我们不想放弃数组,这是不可行的。在这种情况下,我们可以使用智能指针来解决问题。

假设,我们有一个函数ThingType* generateArray(),我们想用它来初始化Things类型的对象。我们应该做的第一件事是用另一个返回智能指针的函数来包装这个函数。

unique_ptr<ThingType[]> generateSmartPointer()
{
return unique_ptr<ThingType[]>(generateArray());
}

在这里,我使用了unique_pointer,但这可能会根据实现而改变。

现在,我们向Things添加一个新的构造函数,并将unique_ptr的实例作为参数。这将充当ThingType:数组的移动构造函数

Things(unique_ptr<ThingType[]> thingsPointer, int sizeOfArray) 
: myArray(thingsInput.release()), size(sizeOfArray)
{  }

unique_ptr<T>.release()用于获取数组,同时使唯一指针释放对它的所有权,防止唯一指针一旦被破坏就被删除。

就是这样。这是我发现的解决这个问题的两个最好的解决方案,虽然它们还远远不够完美,但到目前为止,考虑到每次实施的目标,它们都行之有效。