[英]Immutable “functional” data structure in C++11
我試圖寫下一些我對多線程/並發場景感興趣的數據結構的實現。
很多函數式語言,我所知道的,都是以不可變的方式設計自己的數據結構,所以這意味着如果要為T
的實例t1
增加value
,你真的會得到一個包含t1 + value
的T
新實例。
container t;
container s = t; //t and s refer to the same container.
t.add(value); //this makes a copy of t, and t is the copy
我在C ++ 11中找不到合適的關鍵字; 標准庫中有關鍵字,語義和函數,它們明確地面向功能方法,特別是我發現:
mutable
的不是運行時,它更可能是編譯器的提示,但是這個關鍵字並沒有真正幫助你設計新的數據結構或以不可變的方式使用數據結構 swap
對臨時工作不起作用,這在我的情況下是一個很大的缺點 我也不知道其他關鍵字/功能對這種設計有多大幫助, swap
是其中一個非常接近好的東西,所以我至少可以開始寫東西,但顯然它僅限於lvalue
。
所以我問:用C ++ 11設計不可變的數據結構是否可行?
您只需使用私有成員變量聲明一個類,並且您不提供任何方法來更改這些私有成員的值。 而已。 只從類的構造函數初始化成員。 沒有人能夠以這種方式改變班級的數據。 用於創建不可變對象的C ++工具是成員的私有可見性。
mutable
:這是C ++中最大的攻擊之一。 我一生中最多看到兩個地方,它的使用是合理的,這個關鍵字幾乎與你所尋找的相反。 如果要在C ++中搜索關鍵字以幫助您在編譯時標記數據成員,那么您正在搜索const
關鍵字。 如果將類成員標記為const,則只能從構造函數的INITIALIZER LIST初始化它,並且在實例的整個生命周期內都不能再修改它們。 這不是C ++ 11,它是純C ++。 沒有神奇的語言功能來提供不變性,你只能通過巧妙的編程來實現。
在c ++中, “immutability”由const
關鍵字授予。 當然 - 你仍然可以改變一個const
變量,但你必須故意這樣做(就像這里 )。 在正常情況下,編譯器不會允許您這樣做。 由於您最關注的似乎是以功能樣式進行,並且您想要一個結構 ,您可以自己定義它:
class Immutable{
Immutable& operator=(const Immutable& b){} // This is private, so it can't be called from outside
const int myHiddenValue;
public:
operator const int(){return myHiddenValue;}
Immutable(int valueGivenUponCreation): myHiddenValue(valueGivenUponCreation){}
};
如果你定義一個這樣的類,即使你試圖用const_cast
改變myHiddenValue
,它實際上也不會做任何事情,因為在調用operator const int
期間會復制該值。
注意 :這沒有真正的理由,但是嘿 - 這是你的願望。
另請注意:由於指針存在於C ++中,您仍然可以使用某種指針魔法(獲取對象的地址,計算偏移量等)來更改值,但是您無法真正幫助它。 即使使用函數式語言,如果它有指針,你也無法阻止它。
在旁注 - 為什么你試圖強迫自己以功能的方式使用C ++? 我可以理解它對你來說更簡單,而且你已經習慣了它,但由於它的垮台而不常使用函數式編程。 請注意,無論何時創建新對象,都必須分配空間。 對最終用戶來說速度較慢 。
Bartoz Milewski 用C ++實現了Okasaki的功能數據結構 。 他就功能數據結構對並發性的重要性給出了非常詳盡的論述。 在該論文中,他解釋了並發中構建對象的必要性,然后使其成為不可變的:
這是需要發生的事情:線程必須以某種方式構造它注定不可變的數據。 根據數據的結構,這可能是一個非常簡單或非常復雜的過程。 然后必須凍結該數據的狀態 - 不允許更改。
正如其他人所說,當你想用C ++公開數據並且不能用它來改變時,你可以使你的函數簽名看起來像這樣:
class MutableButExposesImmutably
{
private:
std::string member;
public:
void complicatedProcess() { member = "something else"; } // mutates
const std::string & immutableAccessToMember() const {
return member;
}
};
這是一個可變的數據結構示例,但您無法直接對其進行變更。
我認為你要找的東西就像java的final
關鍵字:這個關鍵字允許你構造一個對象,但此后對象仍然是不可變的。
你可以用C ++做到這一點。 以下代碼示例編譯。 請注意,在類Immutable
,對象member
實際上是不可變的(與前一個示例中的不同):您可以構造它,但是一旦構造,它就是不可變的。
#include <iostream>
#include <string>
using namespace std;
class Immutable
{
private:
const std::string member;
public:
Immutable(std::string a) : member(a) {}
const std::string & immutable_member_view() const { return member; }
};
int main() {
Immutable foo("bar");
// your code goes here
return 0;
}
回覆。 你的代碼示例有s
和t
。 您可以在C ++中執行此操作,但如果我正確理解您的要求,“immutability”與該問題無關!
我在供應商庫中使用了按照你描述的方式運行的容器; 即,當它們被復制時,它們共享它們的內部數據,並且它們不會復制內部數據,直到它們改變其中一個數據為止。
請注意,在您的代碼示例中,要求如果s
發生更改,則t
不得更改。 因此, s
必須包含某種標志或引用計數,以指示t
當前正在共享其數據,因此當s
的數據發生更改時,它需要拆分副本而不是僅更新其數據。
因此,作為容器外觀的一個非常概括的概述:它將包含一些數據的句柄(例如指針),以及引用計數; 並且您更新數據的函數都需要檢查refcount以決定是否重新分配數據; 並且你的copy-constructor和copy-assignment操作符需要增加refcount。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.