将 std::vector<T> 移动到 T*

4

我有一段旧的代码草稿,大致是这样的:

// sadly I have to use this structure
struct LegacyStruct {
  int* values;
}
LegacyStruct* LgStr;
....
    std::vector<int> vec;
    // fill vector in some way here  

    size_t sz = vec.size();
    LgStr->values = new int[sz];
    std::copy(vec.begin(), vec.end(), &LgStr->values[0]);

vec可能很大,我需要避免将其复制到int*中。有没有办法做到这一点?我尝试了以下方法:

// type of new operator explained in More Effective C++
LgStr->values = new (&vec[0])int[vec.size()];

好的,values指向vec内部数组的开头,但当vec超出范围时会被销毁。 但我必须保留它。

&vec[0] = nullptr; // does not compile of course

问题是:在这种情况下是否可以应用移动语义?或者可能有其他技巧吗?

请看这里 https://dev59.com/V1DTa4cB1Zd3GeqPIVUf - sharptooth
2
你能不能直接在LgStr->values上工作,而不是在向量中操作? - mfontanini
1
如果你真正想要的是“释放”vector内部动态分配的int数组,并将该数组的所有权转移给LegacyStruct,以便在vector被销毁后的某个时候使用delete[]删除它:不行。唯一的好消息是,将数据复制到你的数组中肯定不会比首先填充vector更慢,因此错过加速的机会不到50%。 - Steve Jessop
1
只是一个快速的想法(也就是HACK):你可以为std::vector(第二个模板参数)编写自己的分配器,并将deallocate实现为空函数。 - Andre
1
@Andre,这将导致所有向量释放的但您没有拥有权的最终数组之外的内存泄漏。但这可能是正确的方向。 - bames53
显示剩余5条评论
2个回答

6
短暂的回答是,没有办法在vector之外转移其缓冲区的所有权。
我认为您最好的选择是确保使用包装器使vector不会死亡:
class LegacyStructWrapper : private boost::noncopyable  // Or declare private copy constructor/copy assignment or use `= delete` in C++11.
{
private:
    std::vector<int> vec_;
    LegacyStruct wrapped_;
}

那么,每当您需要使用values时,只需将其分配给&vec_[0]。如果/直到您向vector添加更多项,这将保持不变(因此,您必须小心确保矢量调整大小不会引起问题)。


我建议你实现或删除复制构造函数和复制赋值运算符,这样你就不会意外地指向错误的向量了。 - Mike Seymour

4
是的,你可以这样做 - 通过一个小技巧:
struct LegacyStruct {
  std::vector<int> backingStore;
  int* values;
  LegacyStruct(std::vector<int>& aSource) {
    // Steal memory
    aSource.swap(backingStore);
    // Set pointer
    values = &backingStore[0];
  };
}
< p > vector.swap 操作不会复制整数。

当然这会起作用,但我必须向LegacyStruct添加backingStore成员(可能是我在实际代码中要做的方式),这是不可取的,因为其他原因。无论如何,谢谢。 - IgorStack
1
你可以将LegacyStruct包装在另一个类中,并让它处理backingStore管理。这样LegacyStruct就不会改变。 - Basilevs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接