从 unique_ptr 返回引用有时会创建其对象的副本吗?
Does returning a reference from a unique_ptr sometimes create a copy of its object?
下面的代码使用地图中 unique_ptr 的引用来填充对象。 unique_ptr 的后续参考显示没有更新的痕迹。
XSSFWorkbook::CreateCellStyle 是 XSSFCellStyle::CreateCellStyle 工厂函数的客户端。它将 XSSFCellStyle 对象存储在 UPTR__CellStylesMap 中,return 是对它的引用。
XSSFWorkbook::GetStylesheetXml() 稍后获得对每个 XSSFCellStyle 的引用并使用它来输出 XML。
XSSFWorkbook.cpp
// ****************************************************************************
// CreateCellStyle
// ****************************************************************************
XSSFCellStyle&
XSSFWorkbook::CreateCellStyle()
{ map<int, unique_ptr<XSSFCellStyle>>::iterator iter__CellStylesMap;
unique_ptr<XSSFCellStyle> uptr__XSSFCellStyle = nullptr;
uptr__XSSFCellStyle = XSSFCellStyle::CreateCellStyle();
UPTR__CellStylesMap->insert( make_pair( UPTR__CellStylesMap->size(), move( uptr__XSSFCellStyle ) ) );
iter__CellStylesMap = UPTR__CellStylesMap->find( UPTR__CellStylesMap->size() - 1 );
return *iter__CellStylesMap->second
}
// ****************************************************************************
// GetStylesheetXml
// ****************************************************************************
string
XSSFWorkbook::GetStylesheetXml()
{ map<int, unique_ptr<XSSFCellStyle>>::iterator iter__CellStylesMap;
string str___CellStyleXfsXml = "";
// ========================================================================
// Build the XML for the Cell Styles.
// ========================================================================
if( UPTR__CellStylesMap->size() > 0)
{ str___CellStyleXfsXml += "<cellStyleXfs count=\"" + ConvertToString( UPTR__CellStylesMap->size() ) + "\">";
iter__CellStylesMap = UPTR__CellStylesMap->begin();
while( iter__CellStylesMap != UPTR__CellStylesMap->end() )
// { str___CellStyleXfsXml += iter__CellStylesMap->second->GetXml();
{ XSSFCellStyle& xssf__CellStyle = *iter__CellStylesMap->second;
str___CellStyleXfsXml += xssf__CellStyle.GetXml();
iter__CellStylesMap++;
}
str___CellStyleXfsXml += "</cellStyleXfs>";
...
}
/ ****************************************************************************
// GetXml
// ****************************************************************************
string
XSSFWorkbook::GetXml()
{ string str___WorkbookXml = "";
str___WorkbookXml += "<workbook><sheets><sheet name=\"1\" sheetId=\"1\" r:id=\"rId1\" /></sheets></workbook>";
str___WorkbookXml += GetStylesheetXml();
...
return str___WorkbookXml;
}
WinMain 中的这段代码调用 XSSFWorkbook::GetXml(),然后调用 XSSFWorkbook::GetStylesheetXml() 获取对 XSSFCellStyle 对象的引用并打印其 XML.
XSSFCellStyle xssf__CellStyle = xssf__Workbook.CreateCellStyle();
xssf__CellStyle.SetApplyAlignment( true );
uptr__OoxmlTester->SetOoxml( xssf__Workbook.GetXml() );
它return编辑了 XSSFCellStyle::XSSFCellStyle() 初始化列表中设置的默认值,即使 cout 语句显示 XXSFCellStyle: :SetApplyAlignment() 正确设置 ApplyAlignment 属性。
但改用 XSSFCellStyle 参考
uptr__OoxmlTester->SetOoxml( xssf__CellStyle.GetXml() );
做了 return更新值(当然)。
更改 XSSFWorkbook::CreateCellStyle() 使其return成为原始指针
XSSFCellStyle*
XSSFWorkbook::CreateCellStyle()
...
return iter__CellStylesMap->second.get();
和WinMain同样
XSSFCellStyle* ptr___CellStyle = xssf__Workbook.CreateCellStyle();
ptr___CellStyle->SetApplyAlignment( true );
uptr__OoxmlTester->SetOoxml( xssf__Workbook.GetXml() );
返回了更新后的值,表明指针版本确实更新了 UPTR__CellStylesMap 中的 XSSFCellStyle 实例。
我不明白 XSSFWorkbook::CreateCellStyle() 的参考版本如何给我一个 XSSFCellStyle 对象的引用在 UPTR__CellStylesMap(副本?)中,而 XSSFWorkbook::GetCellStyleXml() 中的相同代码 在 UPTR__CellStylesMap.
中获取对 XSSFCellStyle 对象的引用
因为没有 NULL XSSFCellStyle 这样的东西,所以我放弃了参考版本,转而使用 unique_ptr 版本,但我仍然喜欢知道如何永远不要重新创造这个谜团。
P.S。我的编码风格打破常规,让一些人感到不安。请不要让它打扰你。
是的,您正在这一行中创建副本:
XSSFCellStyle xssf__CellStyle = xssf__Workbook.CreateCellStyle();
应该注意的是,正如您暗示的那样,副本不是通过 returning 引用创建的,而是通过使用 returned 引用初始化一个新值来创建的。
如果您想避免复制,您应该将结果存储在引用或指针中。
XSSFCellStyle& xssf__CellStyle = xssf__Workbook.CreateCellStyle();
//or this
XSSFCellStyle* ptr__CellStyle = &xssf__Workbook.CreateCellStyle();
如果你想避免意外复制,那么你应该考虑像这样删除 XSSFCellStyle
的复制构造函数:
XSSFCellStyle( const XSSFCellStyle&) = delete;
我知道这是一种风格决定,但我认为以 Create
开头的函数不应该 return 作为参考。
下面的代码使用地图中 unique_ptr 的引用来填充对象。 unique_ptr 的后续参考显示没有更新的痕迹。
XSSFWorkbook::CreateCellStyle 是 XSSFCellStyle::CreateCellStyle 工厂函数的客户端。它将 XSSFCellStyle 对象存储在 UPTR__CellStylesMap 中,return 是对它的引用。
XSSFWorkbook::GetStylesheetXml() 稍后获得对每个 XSSFCellStyle 的引用并使用它来输出 XML。
XSSFWorkbook.cpp
// ****************************************************************************
// CreateCellStyle
// ****************************************************************************
XSSFCellStyle&
XSSFWorkbook::CreateCellStyle()
{ map<int, unique_ptr<XSSFCellStyle>>::iterator iter__CellStylesMap;
unique_ptr<XSSFCellStyle> uptr__XSSFCellStyle = nullptr;
uptr__XSSFCellStyle = XSSFCellStyle::CreateCellStyle();
UPTR__CellStylesMap->insert( make_pair( UPTR__CellStylesMap->size(), move( uptr__XSSFCellStyle ) ) );
iter__CellStylesMap = UPTR__CellStylesMap->find( UPTR__CellStylesMap->size() - 1 );
return *iter__CellStylesMap->second
}
// ****************************************************************************
// GetStylesheetXml
// ****************************************************************************
string
XSSFWorkbook::GetStylesheetXml()
{ map<int, unique_ptr<XSSFCellStyle>>::iterator iter__CellStylesMap;
string str___CellStyleXfsXml = "";
// ========================================================================
// Build the XML for the Cell Styles.
// ========================================================================
if( UPTR__CellStylesMap->size() > 0)
{ str___CellStyleXfsXml += "<cellStyleXfs count=\"" + ConvertToString( UPTR__CellStylesMap->size() ) + "\">";
iter__CellStylesMap = UPTR__CellStylesMap->begin();
while( iter__CellStylesMap != UPTR__CellStylesMap->end() )
// { str___CellStyleXfsXml += iter__CellStylesMap->second->GetXml();
{ XSSFCellStyle& xssf__CellStyle = *iter__CellStylesMap->second;
str___CellStyleXfsXml += xssf__CellStyle.GetXml();
iter__CellStylesMap++;
}
str___CellStyleXfsXml += "</cellStyleXfs>";
...
}
/ ****************************************************************************
// GetXml
// ****************************************************************************
string
XSSFWorkbook::GetXml()
{ string str___WorkbookXml = "";
str___WorkbookXml += "<workbook><sheets><sheet name=\"1\" sheetId=\"1\" r:id=\"rId1\" /></sheets></workbook>";
str___WorkbookXml += GetStylesheetXml();
...
return str___WorkbookXml;
}
WinMain 中的这段代码调用 XSSFWorkbook::GetXml(),然后调用 XSSFWorkbook::GetStylesheetXml() 获取对 XSSFCellStyle 对象的引用并打印其 XML.
XSSFCellStyle xssf__CellStyle = xssf__Workbook.CreateCellStyle();
xssf__CellStyle.SetApplyAlignment( true );
uptr__OoxmlTester->SetOoxml( xssf__Workbook.GetXml() );
它return编辑了 XSSFCellStyle::XSSFCellStyle() 初始化列表中设置的默认值,即使 cout 语句显示 XXSFCellStyle: :SetApplyAlignment() 正确设置 ApplyAlignment 属性。
但改用 XSSFCellStyle 参考
uptr__OoxmlTester->SetOoxml( xssf__CellStyle.GetXml() );
做了 return更新值(当然)。
更改 XSSFWorkbook::CreateCellStyle() 使其return成为原始指针
XSSFCellStyle*
XSSFWorkbook::CreateCellStyle()
...
return iter__CellStylesMap->second.get();
和WinMain同样
XSSFCellStyle* ptr___CellStyle = xssf__Workbook.CreateCellStyle();
ptr___CellStyle->SetApplyAlignment( true );
uptr__OoxmlTester->SetOoxml( xssf__Workbook.GetXml() );
返回了更新后的值,表明指针版本确实更新了 UPTR__CellStylesMap 中的 XSSFCellStyle 实例。
我不明白 XSSFWorkbook::CreateCellStyle() 的参考版本如何给我一个 XSSFCellStyle 对象的引用在 UPTR__CellStylesMap(副本?)中,而 XSSFWorkbook::GetCellStyleXml() 中的相同代码 在 UPTR__CellStylesMap.
中获取对 XSSFCellStyle 对象的引用因为没有 NULL XSSFCellStyle 这样的东西,所以我放弃了参考版本,转而使用 unique_ptr 版本,但我仍然喜欢知道如何永远不要重新创造这个谜团。
P.S。我的编码风格打破常规,让一些人感到不安。请不要让它打扰你。
是的,您正在这一行中创建副本:
XSSFCellStyle xssf__CellStyle = xssf__Workbook.CreateCellStyle();
应该注意的是,正如您暗示的那样,副本不是通过 returning 引用创建的,而是通过使用 returned 引用初始化一个新值来创建的。
如果您想避免复制,您应该将结果存储在引用或指针中。
XSSFCellStyle& xssf__CellStyle = xssf__Workbook.CreateCellStyle();
//or this
XSSFCellStyle* ptr__CellStyle = &xssf__Workbook.CreateCellStyle();
如果你想避免意外复制,那么你应该考虑像这样删除 XSSFCellStyle
的复制构造函数:
XSSFCellStyle( const XSSFCellStyle&) = delete;
我知道这是一种风格决定,但我认为以 Create
开头的函数不应该 return 作为参考。