My problem is that I have to choose between copying const data, and moving non-const data, and I conceptually do not see a reason why, in my situation, it wouldn't be safe to move const data to a const destination. I am also aware that moving from a const object is illogical - so perhaps there's some other way to achieve what I am attempting to do...
I have a Builder class that sets up a BigData object that I don't want to have to copy around. Once the builder is finished it 'emits' the data as const, because it shouldn't be modified after that point. The builder is temporary, and can then be discarded, but the data should live on, as a const member in a wrapper class that can interrogate it. The builder is a generic type (doesn't know about the details of the data), while the wrapper is specific to the contents of the data. This is achieved via type-erasure within the data, but that's not relevant to this question, except to make it clear that it isn't desirable to merge the builder and wrapper.
The below code describes the above, and does not compile unless you remove BigData's move constructor. The compile error shows that this code would copy the data, which is undesirable:
prog.cpp:26:57: error: use of deleted function ‘constexpr BigData::BigData(const BigData&)’ Wrapper( const BigData&& In ) : Data( std::move(In) ) {} ^
class BigData
{
// Only a builder can create data
friend class Builder;
BigData() = default;
public:
// Move only
BigData( BigData&& ) = default;
};
class Builder
{
BigData Data;
public:
const BigData&& Build() & { return std::move(Data); }
// Functions to set up data go here
};
class Wrapper
{
const BigData Data;
public:
Wrapper( const BigData&& In ) : Data( std::move(In) ) {}
// Functions to query data go here
};
std::unique_ptr<Wrapper> DoBuild()
{
Builder b;
// call functions on b to set up data here
return std::make_unique<Wrapper>( b.Build() );
}
The above code can also be found at https://ideone.com/tFkVEd.
The problem can be fixed by changing all const BigData&&
into just BigData&&
but I don't want the data to be changeable after it is retrieved from Build()
.
Finally, the problem could also be solved by returning the data from Build in a unique_ptr<const BigData>
, and have the Wrapper take ownership of this, but my problem with this is that a pointer can be null, so all usage of Data within Wrapper would have to first check that the Data pointer is valid. This is why I want to move the const data into the wrapper via an rvalue reference, and also why the wrapper must be constructed with the data.
Is there any way to achieve what I want, or have I come up against a limitation of c++?
Many thanks in advance for your input.
NB: Related questions that I have encountered while trying to solve this myself: