How to test for trivially copy assignable lambdas - c++

I'd appreciate if anybody could give me a hint on how to test for trivial copy-ability of a functor (lambdas are meant to be used). As explained in this question it is implementation defined whether lambda is trivially copyable. For example for the code shown at the end of this question gcc (5.4) and msvc (2015) both fire assertions that these are not trivially copy assignable.
I expected these types of lambdas to be represented by struct keeping this pointer and having copy of every captured value (if any). So they all appear to be trivially copyable - at least for the case when the captured values are trivially copyable.
My real use case driving this question is that I'm using a callback (minimalistic version of std::function that does not allocate and is meant for very simple functors) that keeps a fixed buffer in which it copy constructs (in place) passed functor. Then I expected to be able to copy/assign these callbacks but in order for this to work (out of the box) simple mem-copying of these fixed buffers should be equivalent to coping/assigning of the functors kept in them.
So I have two questions:
Imagine that in test_functor() below I do new placement e.g. like
new (&buffer) F(functor)
Is it safe to just memcopy this buffer for the kind of lambdas shown below? I expect this should be so since for all cases there is only this pointer captured or values captured are trivially copyable, but it would be nice if somebody could confirm this.
How can I test whether simple copying of memory where functor is kept is equivalent to copying of the functor? If the answer for the first question is positive then std::is_trivially_copy_assignable not the right answer.
#include <type_traits>
template <typename F>
void test_functor(const F& functor)
{
static_assert(std::is_trivially_destructible<F>::value,
"Functor not trivially destructible");
static_assert(std::is_trivially_copy_constructible<F>::value,
"Functor not trivially copy constructible");
static_assert(std::is_trivially_copy_assignable<F>::value,
"Functor not trivially copy assignable");
}
struct A
{
void test() { test_functor([this]() { }); }
};
struct B
{
void test() { test_functor([this](int v) { value = v; }); }
int value;
};
struct C
{
void test(int v) { test_functor([=]() { value = v; }); }
int value;
};
int main()
{
A a;
B b;
C c;
a.test();
b.test();
c.test(1);
return 0;
}

No it is not safe. If the compiler says something cannot be trivially copied, it cannot be.
It might work. But it working doesn't mean it is safe.
Even if it works today, but tomorrow it stops working after a the compiler updates.
The fix is pretty simple. Write a SBO type (small buffer optimization) that doesn't require trivially copiable.
template<std::size_t S, std::size_t A>
struct SBO {
void(*destroy)(SBO*) = nullptr;
// void(*copy_ctor)(SBO const* src, SBO* dest) = nullptr;
void(*move_ctor)(SBO* src, SBO* dest) = nullptr;
std::aligned_storage_t< S, A > buffer;
void clear() {
auto d = destroy;
destroy = nullptr;
// copy_ctor = nullptr;
move_ctor = nullptr;
if (d) d(this);
}
template<class T, class...Args>
T* emplace( Args&&... args ) {
static_assert( sizeof(T) <= S && alignof(T) <= A, "not enough space or alignment" );
T* r = new( (void*)&buffer ) T(std::forward<Args>(args)...);
destroy = [](SBO* buffer) {
((T*)&buffer->buffer)->~T();
};
// do you need a copy ctor? If not, don't include this:
//copy_ctor = [](SBO const* src, SBO* dest) {
// auto s = (T const*)&src.buffer;
// dest->clear();
// dest->emplace<T>( *s );
//};
move_ctor = [](SBO* src, SBO* dest) {
auto* s = (T*)&src->buffer;
dest->clear();
dest->emplace<T>( std::move(*s) );
src->clear();
};
return r;
}
SBO() = default;
SBO(SBO&& o) {
if (o.move_ctor) {
o.move_ctor(&o, this);
}
}
SBO& operator=(SBO&& o) {
if (this == &o) return *this; // self assign clear, which seems surprising
if (o.move_ctor) {
o.move_ctor(&o, this);
}
return *this;
}
// do you need a copy ctor? If so, implement `SBO const&` ctor/assign
};
live example.
Now here is the punchline. std::function almost certainly already does this for you.
Put a small type with a no-throw move and construct in a std::function and ask if the creation could throw. I'm guessing your implementation will use a SBO to store the type in there.
MSVC 2015 I think has enough room for a lambda storing two std::strings.
The overhead to do things right is modest (two pointers, and a little indirection). You can drop the storage cost down to one pointer per instance at the cost of more indirection (stick the table into a "manual vtable" stored as a static local in a factory function: I can provide a link to examples if that doesn't light a bulb), but with 2 erased methods might as well store them locally (at 3+ consider the static table) unless space is at a premium.
You are already "erasing" invocation, which basically requires storing a function pointer, adding move (and maybe copy) and destroy isn't that much more overhead.

Related

Is it possible to avoid a copy when returning an argument from a function?

Suppose I have value type with some in-place operation. For example, something like this:
using MyType = std::array<100, int>;
void Reverse(MyType &value) {
std::reverse(value.begin(), value.end());
}
(The type and operation can be more complicated, but the point is the operation works in-place and the type is trivially copyable and trivially destructible. Note that MyType is large enough to care about avoiding copies, but small enough that it probably doesn't make sense to allocate on the heap, and since it contains only primitives, it doesn't benefit from move semantics.)
I usually find it helpful to also define a helper function that doesn't change the value in-place, but returns a copy with the operation applied to it. Among other things, that enables code like this:
MyType value = Reversed(SomeFunction());
Considering that Reverse() operates in-place, it should be logically possible to calculate value without copying the result from SomeFunction(). How can I implement Reversed() to avoid unnecessary copies? I'm willing to define Reversed() as an inline function in a header if that's what's necessary to enable this optimization.
I can think of two ways to implement this:
inline MyType Reversed1(const MyType &value) {
MyType result = value;
Reverse(result);
return result;
}
This benefits from return-value optimization but only after the argument value has been copied to result.
inline MyType Reversed2(MyType value) {
Reverse(value);
return value;
}
This might require the caller to copy the argument, except if it's already an rvalue, but I don't think return-value optimization is enabled this way (or is it?) so there's a copy upon return.
Is there a way to implemented Reversed() that avoids copies, ideally in a way that it's guaranteed by recent C++ standards?
If you do want to reverse the string in-place so that the change to the string you send in as an argument is visible at the call site and you also want to return it by value, you have no option but to copy it. They are two separate instances.
One alternative: Return the input value by reference. It'll then reference the same object that you sent in to the function:
MyType& Reverse(MyType& value) { // doesn't work with r-values
std::reverse(std::begin(value), std::end(value));
return value;
}
MyType Reverse(MyType&& value) { // r-value, return a copy
std::reverse(std::begin(value), std::end(value));
return std::move(value); // moving doesn't really matter for ints
}
Another alternative: Create the object you return in-place. You'll then return a separate instance with RVO in effect. No moves or copies. It'll be a separate instance from the one you sent in to the function though.
MyType Reverse(const MyType& value) {
// Doesn't work with `std::array`s:
return {std::rbegin(value), std::rend(value)};
}
The second alternative would work if std::array could be constructed from iterators like most other containers, but they can't. One solution could be to create a helper to make sure RVO works:
using MyType = std::array<int, 26>;
namespace detail {
template<size_t... I>
constexpr MyType RevHelper(const MyType& value, std::index_sequence<I...>) {
// construct the array in reverse in-place:
return {value[sizeof...(I) - I - 1]...}; // RVO
}
} // namespace detail
constexpr MyType Reverse(const MyType& value) {
// get size() of array in a constexpr fashion:
constexpr size_t asize = std::tuple_size_v<MyType>;
// RVO:
return detail::RevHelper(value, std::make_index_sequence<asize>{});
}
Your last option is the way to go (except for the typo):
MyType Reversed2(MyType value)
{
Reverse(value);
return value;
}
[N]RVO doesn't apply to return result;, but at least it's implicitly moved, rather than copied.
You'll have either a copy + a move, or two moves, depending on the value category of the argument.
There is a trick. It is NOT pretty but it works.
Make Reversed accept not a T, but a function returning T. Call it like that:
MyType value = Reversed(SomeFunction); // note no `SomeFunction()`
Here is a full implementation of Reversed:
template <class Generator>
MyType Reversed(Generator&& g)
{
MyType t{g()};
reverse(t);
return t;
}
This produces no copies or moves. I checked.
If you feel particularly nasty, do this
#define Reversed(x) Reversed([](){return x;})
and go back to calling Reversed(SomeFunction()). Again, no copies or moves. Bonus points if you manage to squeeze it through a corporate code review.
You can use a helper method that turns your in-place operation into something that can work on Rvalues. When I tested this in GCC, it results in one move operation, but no copies. The pattern looks like this:
void Reversed(MyType & m);
MyType Reversed(MyType && m) {
Reversed(m);
return std::move(m);
}
Here is the full code I used to test whether this pattern results in copies or not:
#include <stdio.h>
#include <string.h>
#include <utility>
struct MyType {
int * contents;
MyType(int value0) {
contents = new int[42];
memset(contents, 0, sizeof(int) * 42);
contents[0] = value0;
printf("Created %p\n", this);
}
MyType(const MyType & other) {
contents = new int[42];
memcpy(contents, other.contents, sizeof(int) * 42);
printf("Copied from %p to %p\n", &other, this);
}
MyType(MyType && other) {
contents = other.contents;
other.contents = nullptr;
printf("Moved from %p to %p\n", &other, this);
}
~MyType() {
if (contents) { delete[] contents; }
}
};
void Reversed(MyType & m) {
for (int i = 0; i < 21; i++) {
std::swap(m.contents[i], m.contents[41 - i]);
}
}
MyType Reversed(MyType && m) {
Reversed(m);
return std::move(m);
}
MyType SomeFunction() {
return MyType(7);
}
int main() {
printf("In-place modification\n");
MyType x = SomeFunction();
Reversed(x);
printf("%d\n", x.contents[41]);
printf("RValue modification\n");
MyType y = Reversed(SomeFunction());
printf("%d\n", y.contents[41]);
}
I'm not sure if this lack of copies is guaranteed by the standard, but I would think so, because there are some objects that are not copyable.
Note: The original question was just about how to avoid copies, but I'm afraid the goalposts are changing and now we are trying to avoid both copies and moves. The Rvalue function I present does seem to perform one move operation. However, if we cannot eliminate the move operation, I would suggest that the OP redesign their class so that moves are cheap, or just give up on the idea of this shorter syntax.
When you write
MyType value = Reversed(SomeFunction());
I see 2 things happen: Reversed will do RVO so it directly writes to value and SomeFunction either gets coppied into the argument for Reversed or creates a temporary object and you pass a reference. No matter how you write it there will be at least 2 objects and you have to reverse from one to the other.
There is no way for the compiler to do what I would call an AVO, argument value optimization. You want the argument to the Reversed function to be stored in the return value of the function so you can do in-place operations. With that feature the compiler could do RVO-AVO-RVO and SomeFunction would create it's return value directly in the final value variable.
But you could do this I think:
MyType &&value = SomeFunctio();
reverse(value);
Looking at it another way: Say you do figure out a way for Reveresed to do in-place operations then in
MyType &&value = Reversed(SomeFunction());
the SomeFunction would create a temporary but then the compiler has to extend the lifetime of that temporary to the lifetime of value. This works in direct assignment but how is the compiler supposed to know that Reversed will just pass the temporary through?
From the answers and comments it looks like the consensus is that there is no way to achieve this in C++.
It makes sense that this is the general answer without the implementation of MyType Reversed(MyType) available, since the compiler would have no clue that the return value is the same as the argument, so it would necessarily allocate separate spaces for them.
But it looks like even with the implementation of Reversed() available, neither GCC nor Clang will optimize away the copy: https://godbolt.org/z/KW6Y3vsdf
So I think the short story is that what I was asking for isn't possible. If it's important to avoid the copy, the caller should explicitly write:
MyType value = SomeFunction();
Reverse(value);
// etc.

Is std::optional<std::shared_ptr<MyClass>> good for avoiding null point deference?

I want to write safe C++ programs, therefore:
I wanted to avoid memory leaks, so I started using std::shared_ptr.
However, I still had some null pointer deferences some times. I've come up with the idea of using using MyClassSafe = std::optional<std::shared_ptr<MyClass>>.
Then I avoid both memory leaks and null pointer deference. Well, kind of. For example:
MyClassSafe myClassSafe = std::make_shared<MyClass>();
//Then everytime I want to use myClassSafe:
if (myClassSafe) {
//use it here
} else {
//do something in case no value
}
//However, this situation can be possible:
MyClassSafe notVerySafe = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClassSafe) {
//use it here, for example:
//this deferences a nullptr
myClassSafe.value()->someFunction();
} else {
//do something in case no value
}
so this is not much safer. It's better but I still can make mistakes.
I can imagine a safe_shared_ptr<T> class that instead of calling the object's functions on operator->, it could return std::optional<T&> (much like Rust) for which we can then safely call or deal with the std::nullopt case. Isn't there something already in C++? Or can it be implemented easily?
You haven't shown need for either pointers or optionals here.
MyClass myClassSafe;
myClassSafe.someFunction();
No possibility of null pointers or empty optionals in sight.
optional<T> allows you to handle the "no T available" case, which shared_ptr<T> already handles. Therefore optional<shared_ptr<T>> is redundant, just like optional<optional<T>> is.
There is a case to be made for shared_ptr<optional<T>> - if one owner creates the T object, the other owner can see the new object, so that isn't really redundant.
Your use of std::optional here is the cause of the problem. std::shared_ptr defines operator bool as a null pointer check, but because you have wrapped it in std::optional this never gets called
If instead you try:
MyClass myClass = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClass) {
// std::shared_ptr implements operator bool as a null pointer check
myClass->someFunction();
} else {
//do something in case no value
}
Isn't there something already in C++?
There is nothing in std to handle non null smart pointer.
As Caleth shows in his answer, you can use object directly and avoid (smart) pointer and std::optional.
Or can it be implemented easily?
Non null smart pointer (a "smart reference" :) ) should be non default constructible, and "non-movable" (I mean move should not invalidate the reference).
You could implement it with existing smart pointer, something like:
template <typename T>
class unique_ref
{
public:
// Avoid variadic constructor which might take precedence over regular copy/move constructor
// so I use tag std::in_place_t here.
template <typename ... Ts>
unique_ref(std::in_place_t, Ts&&... args) : std::make_unique<T>(std::forward<Ts>(args)...) {}
unique_ref(const unique_ref&) = delete;
unique_ref(unique_ref&&) = delete;
unique_ref& operator=(const unique_ref&) = delete;
unique_ref& operator=(unique_ref&&) = delete;
const T& operator*() const { return *ptr; }
T& operator*() { return *ptr; }
const T* operator ->() const { return ptr.get(); }
T* operator*() { return ptr.get(); }
private:
std::unique_ptr<T> ptr;
};
template <typename T, typename ... Ts>
unique_ref<T> make_unique_ref(Ts&&... args)
{
return {std::in_place, std::forward<Ts>(args)...};
}
unique version is not much useful, as non-copyable, non-movable. using directly T seems simpler.
shared version is copyable (its move should do identical to the copy)
A weak version might return an std::optional<shared_ref<T>>.

Idiomatic way to create an immutable and efficient class in C++

I am looking to do something like this (C#).
public final class ImmutableClass {
public readonly int i;
public readonly OtherImmutableClass o;
public readonly ReadOnlyCollection<OtherImmutableClass> r;
public ImmutableClass(int i, OtherImmutableClass o,
ReadOnlyCollection<OtherImmutableClass> r) : i(i), o(o), r(r) {}
}
The potential solutions and their associated problems I've encountered are:
1. Using const for the class members, but this means the default copy assignment operator is deleted.
Solution 1:
struct OtherImmutableObject {
const int i1;
const int i2;
OtherImmutableObject(int i1, int i2) : i1(i1), i2(i2) {}
}
Problem 1:
OtherImmutableObject o1(1,2);
OtherImmutableObject o2(2,3);
o1 = o2; // error: use of deleted function 'OtherImmutableObject& OtherImmutableObject::operator=(const OtherImmutableObject&)`
EDIT: This is important as I would like to store immutable objects in a std::vector but receive error: use of deleted function 'OtherImmutableObject& OtherImmutableObject::operator=(OtherImmutableObject&&)
2. Using get methods and returning values, but this means that large objects would have to be copied which is an inefficiency I'd like to know how to avoid. This thread suggests the get solution, but it doesn't address how to handle passing non-primitive objects without copying the original object.
Solution 2:
class OtherImmutableObject {
int i1;
int i2;
public:
OtherImmutableObject(int i1, int i2) : i1(i1), i2(i2) {}
int GetI1() { return i1; }
int GetI2() { return i2; }
}
class ImmutableObject {
int i1;
OtherImmutableObject o;
std::vector<OtherImmutableObject> v;
public:
ImmutableObject(int i1, OtherImmutableObject o,
std::vector<OtherImmutableObject> v) : i1(i1), o(o), v(v) {}
int GetI1() { return i1; }
OtherImmutableObject GetO() { return o; } // Copies a value that should be immutable and therefore able to be safely used elsewhere.
std::vector<OtherImmutableObject> GetV() { return v; } // Copies the vector.
}
Problem 2: The unnecessary copies are inefficient.
3. Using get methods and returning const references or const pointers but this could leave hanging references or pointers. This thread talks about the dangers of references going out of scope from function returns.
Solution 3:
class OtherImmutableObject {
int i1;
int i2;
public:
OtherImmutableObject(int i1, int i2) : i1(i1), i2(i2) {}
int GetI1() { return i1; }
int GetI2() { return i2; }
}
class ImmutableObject {
int i1;
OtherImmutableObject o;
std::vector<OtherImmutableObject> v;
public:
ImmutableObject(int i1, OtherImmutableObject o,
std::vector<OtherImmutableObject> v) : i1(i1), o(o), v(v) {}
int GetI1() { return i1; }
const OtherImmutableObject& GetO() { return o; }
const std::vector<OtherImmutableObject>& GetV() { return v; }
}
Problem 3:
ImmutableObject immutable_object(1,o,v);
// elsewhere in code...
OtherImmutableObject& other_immutable_object = immutable_object.GetO();
// Somewhere else immutable_object goes out of scope, but not other_immutable_object
// ...and then...
other_immutable_object.GetI1();
// The previous line is undefined behaviour as immutable_object.o will have been deleted with immutable_object going out of scope
Undefined behaviour can occur due to returning a reference from any of the Get methods.
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 members public.
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.
You can basically get what you want by leveraging a std::unique_ptr or std::shared_ptr. If you only want one of these objects, but allow for it to be moved around, then you can use a std::unique_ptr. If you want to allow for multiple objects ("copies") that all have the same value, then you can use a std::shared_Ptr. Use an alias to shorten the name and provide a factory function and it becomes pretty painless. That would make your code look like:
class ImmutableClassImpl {
public:
const int i;
const OtherImmutableClass o;
const ReadOnlyCollection<OtherImmutableClass> r;
public ImmutableClassImpl(int i, OtherImmutableClass o,
ReadOnlyCollection<OtherImmutableClass> r) : i(i), o(o), r(r) {}
}
using Immutable = std::unique_ptr<ImmutableClassImpl>;
template<typename... Args>
Immutable make_immutable(Args&&... args)
{
return std::make_unique<ImmutableClassImpl>(std::forward<Args>(args)...);
}
int main()
{
auto first = make_immutable(...);
// first points to a unique object now
// can be accessed like
std::cout << first->i;
auto second = make_immutable(...);
// now we have another object that is separate from first
// we can't do
// second = first;
// but we can transfer like
second = std::move(first);
// which leaves first in an empty state where you can give it a new object to point to
}
If the code is changes to use a shared_ptr instead then you could do
second = first;
and then both objects point to the same object, but neither can modify it.
Immutability in C++ can't be directly compared to immutability in most other popular languages because of C++'s universal value semantics. You have to figure out what you want "immutable" to mean.
You want to be able to assign new values to variables of type OtherImmutableObject. That makes sense, since you can do that with variables of type ImmutableObject in C#.
In that case, the simplest way to get the semantics you want is
struct OtherImmutableObject {
int i1;
int i2;
};
It may look like this is mutable. After all, you can write
OtherImmutableObject x{1, 2};
x.i1 = 3;
But the effect of that second line is (ignoring concurrency...) exactly the same as the effect of
x = OtherImmutableObject{3, x.i2};
so if you want to allow assignment to variables of type OtherImmutableObject then it makes no sense to disallow direct assignment to members, since it doesn't provide any additional semantic guarantee; all it does is make the code for the same abstract operation slower. (In this case, most optimizing compilers will probably generate the same code for both expressions, but if one of the members was a std::string they might not be smart enough to do that.)
Note that this is the behavior of basically every standard type in C++, including int, std::complex, std::string, etc. They are all mutable in the sense that you can assign new values to them, and all immutable in the sense that the only thing you can do (abstractly) to change them is assign new values to them, much like immutable reference types in C#.
If you don't want that semantics, your only other option is to forbid assignment. I would advise doing that by declaring your variables to be const, not by declaring all the members of the type to be const, because it gives you more options for how you can use the class. For example, you can create an initially mutable instance of the class, build a value in it, then "freeze" it by using only const references to it thereafter – like converting a StringBuilder to a string, but without the overhead of copying it.
(One possible reason to declare all members to be const might be that it allows for better optimization in some cases. For example, if a function gets an OtherImmutableObject const&, and the compiler can't see the call site, it isn't safe to cache the values of members across calls to other unknown code, since the underlying object may not have the const qualifier. But if the actual members are declared const, then I think it would be safe to cache the values.)
To answer your question, you don't create immutable data structures in C++ because consting references to the whole object does the trick. Violations of the rule are made visible by the presence of const_casts.
If I may refer to Kevlin Henney's "Thinking outside the synchronization quadrant", there are two questions to ask about data:
Is a structure immutable or mutable?
Is it shared or unshared?
These questions can be arranged into a nice 2x2 table with 4 quadrants. In a concurrent context, only one quadrant needs synchronization: shared mutable data.
Indeed, immutable data need not be synchronized because you cannot write to it, and concurrent reads are fine. Unshared data needs not be synchronized, because only the owner of the data can write to it or read from it.
So it is fine for a data structure to be mutable in an unshared context, and the benefits of immutability occur only in a shared context.
IMO, the solution that gives you most freedom is to define your class for both mutability and immutability, using constness only where it makes sense (data that is initalized then never changed):
/* const-correct */ class C {
int f1_;
int f2_;
const int f3_; // Semantic constness : initialized and never changed.
};
You can then use instances of your class C either as mutable or immutable, benefitting of constness-where-it-makes-sense in either case.
If now you want to share your object, you can pack it in a smart pointer to const:
shared_ptr<const C> ptr = make_shared<const C>(f1, f2, f3);
Using this strategy, your freedom spans the whole 3 unsynchronized quandrants while staying safely out of the synchronization quadrant. (therefore, limiting the need of making your structure immutable)
I'd say the most idiomatic way would be that:
struct OtherImmutable {
int i1;
int i2;
OtherImmutable(int i1, int i2) : i1(i1), i2(i2) {}
};
But... that not immutable??
Indeed but you can pass it around as a value:
void frob1() {
OtherImmutable oi;
oi = frob2(oi);
}
auto frob2(OtherImmutable oi) -> OtherImmutable {
// cannot affect frob1 oi, since it's a copy
}
Even better, places that don't need to mutate locally can define its local variables as const:
auto frob2(OtherImmutable const oi) -> OtherImmutable {
return OtherImmutable{oi.i1 + 1, oi.i2};
}
Immutable objects work much better with pointer semantics. So write a smart immutable pointer:
struct immu_tag_t {};
template<class T>
struct immu:std::shared_ptr<T const>
{
using base = std::shared_ptr<T const>;
immu():base( std::make_shared<T const>() ) {}
template<class A0, class...Args,
std::enable_if_t< !std::is_base_of< immu_tag_t, std::decay_t<A0> >{}, bool > = true,
std::enable_if_t< std::is_construtible< T const, A0&&, Args&&... >{}, bool > = true
>
immu(A0&& a0, Args&&...args):
base(
std::make_shared<T const>(
std::forward<A0>(a0), std::forward<Args>(args)...
)
)
{}
template<class A0, class...Args,
std::enable_if_t< std::is_construtible< T const, std::initializer_list<A0>, Args&&... >{}, bool > = true
>
immu(std::initializer_list<A0> a0, Args&&...args):
base(
std::make_shared<T const>(
a0, std::forward<Args>(args)...
)
)
{}
immu( immu_tag_t, std::shared_ptr<T const> ptr ):base(std::move(ptr)) {}
immu(immu&&)=default;
immu(immu const&)=default;
immu& operator=(immu&&)=default;
immu& operator=(immu const&)=default;
template<class F>
immu modify( F&& f ) const {
std::shared_ptr<T> ptr;
if (!*this) {
ptr = std::make_shared<T>();
} else {
ptr = std::make_shared<T>(**this);
}
std::forward<F>(f)(*ptr);
return {immu_tag_t{}, std::move(ptr)};
}
};
This leverages shared_ptr for most of its implementation; most of the disadvantages of shared_ptr are not a problem with immutable objects.
Unlike shared ptr, it permits you to create the object directly, and by default creates a non-null state. It can still reach a null state by being moved-from. You can create one in a null state by doing:
immu<int> immu_null_int{ immu_tag_t{}, {} };
and a non-null int via:
immu<int> immu_int;
or
immu<int> immu_int = 7;
I added a useful utility method called modify. Modify gives you a mutable instance of the T to pass to a lambda to modify before it is returned packaged up in an immu<T>.
Concrete use looks like:
struct data;
using immu_data = immu<data>;
struct data {
int i;
other_immutable_class o;
std::vector<other_immutable_class> r;
data( int i_in, other_immutable_class o_in, std::vector<other_immutable_class> r_in ):
i(i_in), o(std::move(o_in)), r( std::move(r_in))
{}
};
Then use immu_data.
Accessing members requires -> not ., and you should check for null immu_datas if you are passed them.
Here is how you use .modify:
immu_data a( 7, other_immutable_class{}, {} );
immu_data b = a.modify([&](auto& b){ ++b.i; b.r.emplace_back() });
This creates a b whose value is equal to a, except i is incremented by 1, and there is an extra other_immutable_class in b.r (default constructed). Note that a is unmodified by creating b.
There are probably typos above, but I've used the design.
If you want to get fancy, you can make immu support copy-on-write, or modify-in-place if unique. It is harder than it sounds though.
C++ doesn't quite have the ability to predefine a class as immutable or const.
And at some point you'll probably come to the conclusion that you shouldn't use const for class members in C++. It's just not worth the annoyances, and honestly you can do without it.
As a practical solution, I would try:
typedef class _some_SUPER_obtuse_CLASS_NAME_PLEASE_DONT_USE_THIS { } const Immutable;
to discourage anyone from using anything but Immutable in their code.
The issue at hand is a mistranslation from C# to C++. In C++ there is simply no* need to do this:
class ImmutableObject {
ImmutableObject(int i1, int i2) : i1(i1), i2(i2) {}
const int i1;
const int i2;
}
ImmutableObject o1(1,2):
ImmutableObject o2(2,3);
o1 = o2; // Doesn't compile, because immutable objects are by definition not mutable.
In your C# example you are using a class. And a variable that holds an instance of a class in C# is really just a reference to a garbage collected object. The closest equivalent in C++ is a reference counted smart pointer. So your c# example is translated to C++ as:
class ImmutableObject {
ImmutableObject(int i1, int i2) : i1(i1), i2(i2) {}
const int i1;
const int i2;
}
std::shared_ptr<ImmutableObject> o1 = std::make_shared<ImmutableObject>(1,2);
std::shared_ptr<ImmutableObject> o2 = std::make_shared<ImmutableObject>(2,3);
o1 = o2; // Does compile because shared_ptr is mutable.
There are several options if you want a mutable reference to an immutable/const object, specifically you can use a pointer, a smart pointer, or a reference_wrapper. Unless you actually want to have a class whose content can be changed by anyone at any time, which is the opposite of an immutable class.
*Of course, C++ is a language where "no" doesn't exist. In those precious few truly exceptional circumstances you can use const_cast.

Correct usage of unique_ptr in class member

I am trying to really move from c++98 to c++11 and newer. I have wrapped my head over most of the new stuff but I am still not sure about the correct usage of unique_ptr.
Consider the example below, where class A has a unique_ptr member (I would have used raw pointer before!). This member variable should be assigned, when user needs, by calling a function somewhere else (not part of the class). Is this the correct usage? If not, what is the best alternative?
class A {
private:
unique_ptr<MyType> mt;
public:
void initStuff() {
mt.reset(std::move(StaticFuncSomewhereElese::generateMyType()));
}
};
MyType* StaticFuncSomewhereElese::generateMyType() {
MyType* temp = new MyType(...);
//do stuff to temp (read file or something...)
return temp;
}
Your code works fine (although the redundant* move can be omitted) but it would be better to construct the unique_ptr as early as possible:
class A {
private:
std::unique_ptr<MyType> mt;
public:
void initStuff() {
mt = StaticFuncSomewhereElese::generateMyType();
}
};
std::unique_ptr<MyType> StaticFuncSomewhereElese::generateMyType() {
auto temp = std::make_unique<MyType>(…);
// `make_unique` is C++14 (although trivially implementable in C++11).
// Here's an alternative without `make_unique`:
// std::unique_ptr<MyType> temp(new MyType(…));
//do stuff to temp (read file or something...)
return temp;
}
This way it is clear that the return value of generateMyType must be deleted by the caller, and there's less possibility for memory leaks (e.g. if generateMyType returns early).
* The move is redundant because:
Raw pointers can't be moved.
The result of the generateMyType() expression is already an rvalue anyways.
Is this the correct usage?
Besides std::move being redundant, yes this is correct. It is redundant because a) Bare pointers are copied, whether they are lvalues or rvalues and b) The function doesn't return a reference, so the return value is already an rvalue so there is no need to convert.
But there is room for improvement. In particular, I recommend to return a unique pointer from the factory function:
std::unique_ptr<MyType> StaticFuncSomewhereElese::generateMyType()
This prevents temp from leaking if the initialization throws an exception, and makes it much harder for the user of the factory to accidentally leak the returned pointer.
Why not make it a generic template factory?
In header.
template <typename T>
std::unique_ptr<T> generateMyType();
classss A {
private:
std::unique_ptr<MyType> mt;
std::unique_ptr<MyOtherType> mot;
public:
void initStuff() {
mt = generateMyType<MyType>();
mot = generateMyType<MyOtherType>();
}
};
And in the source file
template <typename T>
std::unique_ptr<T> generateMyType()
{
auto temp = std::make_unique<T>();
return temp;
}

Non-owning holder with assignment semantics

I have a class that should hold a reference to some data, without owning that data (i.e. the actual data is guaranteed not to go out of scope). In particular, the class cannot make a copy – the data is easily several gigabytes in size.
Now, the usual implementation (I assume) is to have a reference to the data:
struct holder_ref {
type const& value;
holder_ref(type const& value) : value(value) { }
};
(Please note that the constness has absolutely no bearing on the problem).
Now, I absolutely need this class to be assignable (i.e. have a working operator =). I thought this was a fairly common problem but I can’t remember how (if ever) I’ve solved it before.
The problem is that a reference cannot be assigned and there’s simply no way around this. The only solution I’ve come up with uses placement new in place of the assignment operator:
// x = other_x; gets replaced with:
x.~T();
new (&x) T(other_x);
Now, this works and is standard compliant. But it sure is ugly. No – inacceptable.
So I’m searching for alternatives. One idea is to use pointers, but I’m unsure whether my constructor is actually guaranteed to work (and passing a pointer is impossible due to the interface I have to adhere to):
struct holder_ptr {
type const* value;
// Is this legal?
holder_ptr(type const& value = 0) : value(&value) { }
};
But I’d rather use a reference, if at all possible. Only – how to implement the assignment operator?
struct holder_ref {
type const& value;
holder_ref(type const& value = 0) : value(value) { }
holder_ref& operator =(holder_ref const& other) {
// Now what?!
return *this;
}
};
As a test case, consider the following code:
int main() {
int const TEST1 = 23;
int const TEST2 = 13;
int const TEST3 = 42;
std::vector<holder_ptr> hptr(1);
std::vector<holder_ref> href(2);
// Variant 1. Pointer.
hptr[0] = holder_ptr(TEST1);
// Variant 2. Placement new.
href[0].~holder_ref();
new (&href[0]) holder_ref(TEST2);
// Variant 3. ???
href[1] = holder_ref(TEST3);
assert(*hptr[0].value == TEST1); // Works (?)
assert(href[0].value == TEST2); // Works
assert(href[1].value == TEST3); // BOOM!
}
(Also, just to make this clear – the type we’re talking about is non-POD and I need a standard compliant solution.)
I don't see anything wrong with using a holder_ptr. It can be implemented something like so:
struct bad_holder : std::exception { };
struct holder_ptr {
holder_ptr() : value(0) { }
holder_ptr(type const& value) : value(&value) { }
type const& get() {
if (value == 0) throw bad_holder();
return *value;
}
private:
type const* value;
};
So long as you always assign to the pointer from a reference, you know that you have a valid object (that, or you ended up with a "null reference" previously, in which case you have other, bigger problems since you'll already have invoked undefined behavior).
With this solution, the interface is implemented entirely in terms of references, but under the hood a pointer is used so that the type is assignable. The use of references in the interface ensures there are none of the concerns that come with using pointers (namely, you never have to worry whether the pointer is null).
Edit: I've updated the example to allow for the holder to be default constructible.
I'd use the pointer holder. But if you are dead set against that, how about hiding your placement new operator=:
holder_ref& operator =(holder_ref const& other) {
new (this) holder_ref(other);
return *this;
}
Is a TR1 weak_ptr standard compliant enough?