C++是否支持与STL兼容的不可变记录类型?

Moh*_*han 2 c++ const mutable immutability

许多语言都支持不可变类型 - 一旦构造了这种类型的值,就无法以任何方式对其进行修改.我不会偏离这些类型的好处,因为这已在其他地方广泛讨论过.(参见http://codebetter.com/patricksmacchia/2008/01/13/immutable-types-understand-them-and-use-them/)

我想在C++中创建一个轻量级的不可变记录类型.这样做的一个显而易见的方法是const所有成员.例如:

struct Coordinates {
    const double x;
    const double y;
};
Run Code Online (Sandbox Code Playgroud)

不幸的是,以这种方式声明的类型不支持复制赋值,因此不能与STL容器一起使用,这是一个相当致命的缺点.我认为没有任何方法可以解决这个问题,但如果有人能看到,我会很感激.

至于它的价值,据我所知,C++正在混淆两件事:a)你是否可以为变量赋值,b)是否可以在构造之后修改"values"(= objects).在例如Scala中,区别更加清晰

  • valvs var:a var可以有一个绑定到它的新值,一个val不能
  • 不可变和可变对象,尤其是集合

所以我可以写下面的内容:

val val_mutable = collection.mutable.Map(1 -> "One")
val val_immutable = collection.immutable.Map(1 -> "One")
var var_mutable = collection.mutable.Map(1 -> "One")
var var_immutable = collection.immutable.Map(1 -> "One")
Run Code Online (Sandbox Code Playgroud)

vars可以反弹以指向其他值:

//FAILS: val_immutable = collection.immutable.Map(2 -> "Two")
//FAILS: val_mutable = collection.mutable.Map(2 -> "Two")
var_mutable = collection.mutable.Map(2 -> "Two")
var_immutable = collection.immutable.Map(2 -> "Two")
Run Code Online (Sandbox Code Playgroud)

可修改的集合可以修改:

val_mutable(2) = "Two"    
//FAILS: val_immutable(2) = "Two"    
var_mutable(2) = "Two"    
//FAILS: var_immutable(2) = "Two"    
Run Code Online (Sandbox Code Playgroud)

在C++中,const类型的数据成员使其成为不可变类型,但也无法创建该类型的"var".没有后者,任何人都可以看到实现前者的合理轻量级方式吗?[请注意"轻量级"部分 - 特别是,我不想为每个元素创建一个访问器函数struct,因为这会导致可读性大幅下降.

Bri*_*ian 6

请记住,大多数其他语言中的赋值行为类似于C++中的指针重新赋值.

因此,std::shared_ptr<const T>C++中的语义与其他语言中的不可变类型具有相似的语义.

struct Coordinates {
    double x;
    double y;
};
std::shared_ptr<const Coordinates> p = std::make_shared<const Coordinates>(Coordinates{3.14, 42.0});
p->x *= 2;                                           // error; pointee is immutable
p = std::make_shared<const Coordinates>(Coordinates{6.28, 42.0}); // ok
Run Code Online (Sandbox Code Playgroud)