-
You truly want immutable objects of some type plus value semantics (as you care about runtime performance and want to avoid the heap). Just define a
struct
with all data memberspublic
.struct Immutable { const std::string str; const int i; };
You can instantiate and copy them, read data members, but that’s about it. Move-constructing an instance from an rvalue reference of another one still copies.
Immutable obj1{"...", 42}; Immutable obj2 = obj1; Immutable obj3 = std::move(obj1); // Copies, too obj3 = obj2; // Error, cannot assign
This way, you really make sure every usage of your class respects the immutability (assuming no one does bad
const_cast
things). Additional functionality can be provided through free functions, there is no point in adding member functions to a read-only aggregation of data members. -
You want 1., still with value semantics, but slightly relaxed (such that the objects aren’t really immutable anymore) and you’re also concerned that you need move-construction for the sake of runtime performance. There is no way around
private
data members and getter member functions:class Immutable { public: Immutable(std::string str, int i) : str{std::move(str)}, i{i} {} const std::string& getStr() const { return str; } int getI() const { return i; } private: std::string str; int i; };
Usage is the same, but the move construction really does move.
Immutable obj1{"...", 42}; Immutable obj2 = obj1; Immutable obj3 = std::move(obj1); // Ok, does move-construct members
Whether you want assignment to be allowed or not is under your control now. Just
= delete
the assignment operators if you don’t want it, otherwise go with the compiler-generated one or implement your own.obj3 = obj2; // Ok if not manually disabled
-
You don’t care about value semantics and/or atomic reference count increments are ok in your scenario. Use the solution depicted in @NathanOliver’s answer.