移动语义以从缓冲区获取数据的所有权?

时间:2013-11-18 16:53:24

标签: c++ c++11 move-semantics

我目前处理一些数据记录,使用缓冲区,即在录制期间,数据存储在map中,当录制结束时,此地图用于构建CaptureRecord被推送到全局记录(类型std::vector<CaptureRecord>),该记录存储到目前为止完成的每个记录。

最后一部分的代码如下所示:

void CaptureRecorder::stopDataRecording()
{
    OutputDebugString(L"Stopping data recording\n");
    //Omitted stuff

    //The CaptureRecord ctor takes a map as parameter
    m_globalRecord.emplace_back(m_currentCaptureElements);
    m_currentCaptureElements.clear();

    //Omitted stuff
}

问题在于,如果这两行看起来需要花费一些时间(最多几秒),那么时间会与记录的大小成比例增加(这使我很明显这里的副本有问题)

所以我想要做的是,在通过CaptureRecord创建emplace_back()时,它会拥有m_currentCaptureElement中包含的日期的所有权。事实是,我真的不知道该怎么做。我尝试使用移动语义,即使用std::move()作为emplace_back()的参数,以及CaptureRecord的ctor的以下代码:

CaptureRecord(std::map<int, ProcessedCaptElem> record):
    recordContent(std::move(record))
{
    for(auto& recordElement : recordContent){
        m_timestamps.emplace_back(recordElement.second.timestamp);
        m_intensities.emplace_back(recordElement.second.calculatedIntensity);
    }
}

但它似乎没有任何影响(这让我相信它仍然“无法”从变量m_currentCaptureElements移动。)

所以我的问题是:

是否可以做这样的事情(从某种缓冲区移动,然后重置它)以及如何做?

注意:我完全接受不涉及移动语义的建议。这些是我能想到的最接近传递数据而不复制的数据,但可能还有其他解决方案,我可能已经错过了不涉及移动。

2 个答案:

答案 0 :(得分:2)

首先,您要将m_currentCaptureElements的内容传输到另一个对象。所以你需要move它。

m_globalRecord.emplace_back(std::move(m_currentCaptureElements));
m_currentCaptureElements.clear();

现在,为了利用赋予CaptureRecord构造函数的rvalue映射,您需要一个构造函数重载,它接受对映射的右值引用。

CaptureRecord(std::map<int, ProcessedCaptElem>&& record):
    recordContent(std::move(record))
{
    // ...
}

如果您需要在地图外单独存储时间戳和计算强度的副本,则无法从地图中移动项目,前提是您还要保留地图的副本。如果您不需要地图,可以将构造函数更改为

CaptureRecord(std::map<int, ProcessedCaptElem>&& record)
{
    for(auto&& recordElement : record){
        m_timestamps.emplace_back(std::move(recordElement.second.timestamp));
        m_intensities.emplace_back(std::move(recordElement.second.calculatedIntensity));
    }
}

假设您还需要一个带左值的重载,您可以创建另一个将项目复制出地图的构造函数。

CaptureRecord(std::map<int, ProcessedCaptElem> const& record)
   recordContent(record)
{
    for(auto const& recordElement : recordContent){
        m_timestamps.push_back(recordElement.second.timestamp);
        m_intensities.push_back(recordElement.second.calculatedIntensity);
    }
}

答案 1 :(得分:1)

我不清楚你正在处理的某些类型是什么,以及某些事情是如何构建的。但是从我可以收集的内容来看,你的CaptureRecord构造函数几乎是正确的。你错过了什么std::move s ...

m_timestamps.emplace_back(std::move(recordElement.second.timestamp));
m_intensities.emplace_back(std::move(recordElement.second.calculatedIntensity));

此外,您可以reserve m_timestampsm_intensities。这可能有助于提高性能。您还必须通过CaptureRecord构建std::move地图...

CaptureRecord cap(std::move(myMap));

在任何地方使用std::move 您的意思是将所有权从一个地方转移到另一个地方。另外需要注意的是,您std::move的任何对象都必须具有移动构造函数/移动赋值运算符。如果您正在使用VS,它将不会像复制构造函数/复制赋值运算符那样为您生成它们。这应该。它没有。你必须明确地做到这一点。