2016-09-26 68 views
17

Herb Sutter's talk at CppCon16中,他建議用const std::unique_ptr(大約10分鐘)寫作pimpl成語。使用const std :: unique_ptr獲取pimpl成語

這應該如何與移動構造函數/作業?在C++ 17中有什麼嗎?我找不到任何東西。

+0

沒有讀過這篇演講,很明顯pimpl的類不可複製/移動。它們將在動態範圍內實例化,並通過智能指針完全訪問,pimpl隱藏了內部實現細節。 –

+6

爲什麼你不希望你的大多數pimpl類可移動?這似乎是一個完全合理的事情。 –

+1

@DenisYaroshevskiy只能假設他有一個特定的用例。一般來說,我會同意使用'unique_ptr'作爲pimpl的容器。如果你希望它是可複製的,那麼當然你需要用克隆操作來實現它。 –

回答

2

這是假設如何使用移動構造函數/賦值?

Move constructors

的隱式或聲明爲已刪除如果任一下列條件爲真被定義爲T類默認的移動構造函數:

  • T具有非無法移動的靜態數據成員(已刪除,無法訪問或含糊不清的移動構造函數)

const std::unique_ptr是這樣一個數據成員,因爲const

如果const被丟棄,編譯器會生成移動構造函數和賦值,但不會生成複製的構造函數和賦值。


草本解釋了爲什麼他使用const unique_ptr

非const可以工作過,但它是更脆弱,因爲默認情況下移動語義可能是不正確。

使用const成員,它更健壯,因爲const成員必須在構造函數中初始化。而const文件表示該對象的執行沒有改變,它不是狀態或策略設計模式。

+0

然後在這種情況下,人們將不得不實施複製構造函數? – vordhosbn

+0

@vordhosbn如果這是必要的。 –

+0

這是真的,但我的問題是關於移動建設/任務。使用簡單的unique_ptr而不是const將保持移動構造/賦值活着,同時聲明它爲const禁止它。 我曾經認爲const數據成員是一個不好的習慣(因爲這個問題),但顯然Herb Sutter不這麼認爲。我想知道爲什麼。 –

8

如果你的類不應該是空的,那麼非const唯一的ptr(帶有默認的移動/賦值)是不合適的。移動ctor和移動分配都將清空rhs。

一個const unique ptr將禁用這些自動方法,如果你想移動,你將不得不在impl(和一些外部的膠水)內寫入它。

我會親自用我想要的語義編寫一個值ptr(然後讓編譯器編寫膠水),但是以const unique_ptr開頭聽起來合理,因爲第一遍是合理的。

如果你放鬆了永不消逝的空間,並且幾乎從不空虛,那麼你現在必須推理許多方法的先決條件,以及可能發生的連鎖錯誤。

這種技術的最大代價是返回值的困難,C++ 17消失了。

+2

如果你從一個對象中移出它假設處於部分形成狀態,所以它只能被分配和析構,所以移動構造器/分配不會破壞你的not_null保證。如果你願意的話,你可以拿出來像gn的not_null一樣包裝它。 –

+0

@DenisYaroshevskiy不,它處於你願意保證的狀態?它不是「應該處於部分形成的狀態」,除非這是你*選擇*保證的。一種選擇是幾乎不會空的,並且一旦移動就只能是空的。這是一個選擇,它有成本和收益。不應該忽視從不空虛到幾乎不空虛的成本。同樣是從幾乎從不空虛到永不空虛的成本。永不空白更容易*保證正確性,並且通過更快速的代碼偏向更經常正確的代碼通常是一個好主意。 – Yakk

+0

@Yakk即使移動對象是「從不空」,移動後使用它是一種強烈的代碼味道。我認爲pimpl指針檢查後跟assert /異常優於允許人們依賴於處於「默認」狀態的移動對象。當由於不可避免的使命蔓延而無法保證擔保時,這是一場災難。我會盡量說這是一種與「std :: move」精神不符的反模式。 –