我想知道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
数组从函数返回为右值。
在这种情况下,我们不关心保留作为参数传递的指针。事实上,我们肯定不想要对它进行深层复制,因为这将浪费大量时间来保留我们即将要销毁的东西。
一个可能的解决方案是添加另一个构造函数来处理非const rvalue ThingType
指针的情况,就像一般移动构造函数处理类的非const rvalue实例的情况一样:
public:
Things(ThingType*&& arrayOfThings, int sizeOfArray)
: myArray(arrayOfThings)
{
arrayOfThings = NULL;
}
这似乎是为我解决问题,但我没有找到有关上面所见的<type>*&&
构造的更多信息。它是犹太洁食,还是我会被送到地下城混合指针和参考?
答案 0 :(得分:0)
过了一段时间后,我相信我找到了令人满意的 - 尽管远非最佳 - 解决方案。由于没有人回答这个问题,我将分享我找到的最佳解决方法。
正如贾斯汀指出的那样,当我们采用变量ThingType*&&
(但不是ThingType
指针的地址时,使用ThingType
会导致麻烦,正如他在答案中暗示的那样)在构造函数调用中。
如果t
是ThingType
,则表达式&t
是ThingType*
类型的r值,因此Thing myThing(&t, ...)
将调用移动构造函数,使myThing.myArray
指向t
的结果。在大多数情况下,这不是我们想要的。
一种解决方案是使用向量而不是数组,如下所示:
// Copy
explicit Things(const std::vector<ThingType>& vectorOfThings)
: myVector(vectorOfThings)
{ }
// Move
explicit Things(std::vector<ThingType>&& vectorOfThings)
: myVector(std::move(vectorOfThings))
{ }
然后在这种情况下使用移动构造函数:
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()
用于获取数组,同时使唯一指针释放对它的所有权,防止在唯一指针被销毁后删除数组。
就是这样。这是我发现这个问题的两个最佳解决方案,虽然它们远非完美,但到目前为止它们已经考虑到了每个实现的目标。