2015-09-28 69 views
1

我有一个rapidjson包装,做以下的不必要的副本:如何防止物体

class ADocument 
{ 
    void setJson(const char *data) { m_D.parse(data); } 

    AData operator[](const char *key) const 
    { 
     const rapidjson::Value *value = rapidjson::Pointer(key).Get(m_D); 

     if(value) 
      return AData(value); 
     else 
      return AData(&m_D); 
    } 

private: 
    rapidjson::Document m_D; 
}; 

AData类是这样的:

class AData 
{ 
public: 
    Adata(const rapidjson::Value *val) : m_Value(val) {} 

    operator QString() const { return m_Value.IsString() ? m_Value.GetString() : QString(); } 

private: 
    const rapidjson::Value *m_Value; 
}; 

而且整个事情是这样调用:

ADocument doc; 
doc.setJson("{\"Hello\":{\"Hello\":\"test\"}}"); 

QString str = doc["/Hello/Hello"]; 
str变为 “测试”

现在,通过调试这个代码我发现该AData对象以某种方式移动 - 的operator QString()会从在不同的存储器位置的对象比原始AData对象调用中的ADocumentoperator[]构造。正则构造函数被调用一次。但可能是copy-elision只是在内存中移动相同的对象。

然而,当我定义的规则的三/ 5方法之一,如AData析构函数不改变任何东西(和析构函数什么也不做本身),那么operator QString()上调用同一对象(同一内存位置),其在ADocumentoperator[]中构建。

即使当我实现了所有可想象的构造函数和运算符(move,copy,assign ...)时,它们中的任何一个都不会被调用,但结果是相同的 - 只创建一个对象。

这是怎么回事?我想了解它。

此外,如何改变这个实现,以便尽可能提高性能和内存效率(=最小副本等)?或者,也许我真的很担心没有什么,我所看到的仅仅是一些编译器优化?

+0

什么是AConstData? –

+0

@AlanStokes对不起,错字。我从我的源代码复制了我实际上有两个类AData和AConstData的代码。我用后者进行了一些测试,但它们都是相同的。 – Resurrection

+1

声音像复制elision正在按预期工作,有什么问题?我认为你不用担心,应该让编译器完成它的工作。 –

回答

1

这是怎么回事?我想了解它。

您正在使用复制elision

当一个未命名的临时文件将被复制或移动到一个相同类型的变量中时,编译器可以直接在该变量中构造该对象并跳过复制或移动操作。

您可能会遇到这种情况的另一种情况是当您从函数中返回具有自动存储持续时间的变量时。