I have a C++ class A that can be constructed to perform a certain computation using a function A::compute . This function requires to write to a preallocated memory area (working area) that was allocated at construction of A to perform this computation efficiently. I would like to A::compute to be const in relation to the class, because the computation does not alter the logical state of the object.
Is this a case when the keyword mutable should be used?
Example code:
class A {
public:
A(size_t size) : m_workingArea(size) {}
int compute(const std::vector<int>& data) const {
// ... checks ...
std::copy(data.begin(), data.end(), m_workingArea.begin());
// ... compute ...
// return a result, say first element of the working area
return m_workingArea[0];
}
private:
mutable std::vector<int> m_workingArea;
};
It is perfectly reasonable to use mutable in this case.
While it is not physically const, the compute(...) method is logically const. That is, to an outside user, compute(...) leaves the object unchanged, despite any internal changes.
Here in the isocpp.org FAQ, the Standard C++ committee recommends that we should prefer logical const over physical const.
Given this, it makes sense to mark m_workingArea mutable, so that compute(...) can be const and logical const-correctness can be maintained. The effect of this should be a clear user interface and clearly stated programmer intent.
To me it looks like a misuse since you are changing the object, but if you really want a fixed size area that you can modify even when this is const, you could keep a pointer to that area and then you don't need to make it mutable:
#include <memory>
#include <vector>
class A {
public:
A(size_t size) : m_workingArea(std::make_unique<int[]>(size)) {}
int compute(const std::vector<int>& data) const {
// ... checks ...
std::copy(data.begin(), data.end(), m_workingArea.get());
// ... compute ...
// return a result, say first element of the working area
return m_workingArea[0];
}
private:
std::unique_ptr<int[]> m_workingArea;
};
Related
I have a class which internally owns a vector of foo
class bar {
private:
vector<Foo> foos_;
}
Now I want to design public access to this vector. I am thinking of two versions of the function:
Foo& getFoo(int index) {
// first do size checking, return ref
return foos[index];
}
and
const Foo& getFoo(int index) const {
// first do size checking, return const reference
return foos[index];
}
Any downside of this approach? One obvious downside is I copy the almost identical code simply twice. Is there a better way to do this?
----- edit -----
the second accessor forgets const, updated
Having both const and non-const accessors is somewhat common in C++. There is no language feature to combine the code for both--you really do need to write it twice.
By the way, you don't need to do bounds checking yourself, you can use foos_.at(index) instead of foos_[index] and then you'll have automatic bounds checking.
Basically, I have the following situation. Note: void* is used to denote arbitrary data, it is strongly typed in a real application.
class A
{
public:
//uses intermediate buffer but doesn't change outward behavior
//intermediate buffer is expensive to fill
void foo(void* input_data);
//uses intermediate buffer and DOES explicitly change something internally
//intermediate buffer is expensive to fill
void bar(void* input_data);
//if input_data hasn't changed since foo, we can totally reuse what happened in foo
//I cannot check if the data is equal quickly, so I allow the user to pass in the
//assertion (put the honerous on them, explicitly tell them in the comments
//that this is dangerous to do, ect)
void bar(void* input_data, bool reuse_intermediate);
private:
void* intermediate_buffer_;
void* something_;
};
So trying for const correctness, intermediate_buffer_ is never exposed so it sortof fits the definition for using a mutable variable. If i never reused this buffer, or I checked for equal input_data before using the cached values, that would be the end of the story, but because of the reuse_intermediate I feel like I'm half exposing it, so I'm not sure whether or not the following makes sense.
class A
{
public:
//uses intermediate buffer but doesn't change something
//intermediate buffer is expensive to fill
void foo(void* input_data) const;
//uses intermediate buffer and DOES explicitly change something internally
//intermediate buffer is expensive to fill
void bar(void* input_data);
//if input_data hasn't changed since foo, we can totally reuse what happened in foo
//I cannot check if the data is equal quickly, so I allow the user to pass in the
//assertion (put the honerous on them, explicitly tell them in the comments
//that this is dangerous to do, ect)
void bar(void* input_data, bool reuse_intermediate);
//an example of where this would save a bunch of computation, though
//cases outside the class can also happen
void foobar(void* input_data)
{
foo(input_data);
bar(input_data,true);
}
private:
mutable void* intermediate_buffer_;
void* something_;
};
Thoughts?
I think this is improper use of mutable. In my experience mutable is used for ancillary private member variables that by their very nature can not be declared const, but do not modify the "conceptual constness" of the public interface.
Take for example a Mutex member variable and a 'thread-safe getter':
class Getter {
public:
Getter( int d, Mutex & m ) : guard_( m ), data_( d ) { };
int get( ) const { Lock l(guard_); return data_; };
private:
mutable Mutex guard_;
const int data_;
};
The main point here is that the data declared mutable (in this case the guard) does change (it's locked and unlocked) but this has no impact on constness from the users perspective. Ultimately, despite the mutable Mutex, you still can't change the const data_ member variable and the compiler enforces this.
In your case, you really want the intermediate_buffer to be const but you explicitly tell the compiler it's not by declaring it mutable. The result is that you can change the data and the compiler can't do a thing about it.
See the difference?
If you really want the interface to live up to the const agreement, make it explicit via something like this:
class A {
public:
A( void* input_data );// I assume this deep copies.
void foo() const;
void bar();
private:
const void* intermediate_buffer_;
void* something_;
};
Now the onus is truly on the user and enforced by the compiler regardless of what the comments say and without any use of mutable. If they know that input_data has changed, they'll have to create a new one, preferably const.
Instead of hiding the intermediate object inside the const object, expose it and let foo and bar return a copy. You are making it very explicit that the intermediate object is being shared, and providing a new capability to keep more than one on hand. If you want to hide the implementation details you can expose an empty class and make the intermediate object a child of this base class.
class A
{
public:
class Intermediate
{
//empty
};
//uses intermediate buffer but doesn't change outward behavior
//intermediate buffer is expensive to fill
//if cache_ptr is NULL the intermediate buffer is discarded
void foo(void* input_data, Intermediate** cache_ptr = NULL) const;
//uses intermediate buffer and DOES explicitly change something internally
//intermediate buffer is expensive to fill
void bar(void* input_data, Intermediate** cache_ptr = NULL);
private:
class IntermediateImpl : public Intermediate
{
//...
};
void* something_;
};
To answer your question directly.
If the function foo is const, calling it at any time should never alter the result of the next operations.
for example:
A a(some_big_data);
a.bar(some_big_data, true);
should give exactly the same result as (excluding performance differences)
A a(some_big_data);
a.foo(some_different_big_data);
a.bar(some_big_data, true);
Since foo is const, users will expect the result to be the same.
If this is the case then making the buffer mutable is reasonable.
Otherwise, it is probably wrong.
Hope this helps
Disclaimer: I am not advocating the use of void* with my answer, I hope that this was simply for demonstration purposes and that you don't actually need to use it yourself.
If a lot of computations can be saved when reusing the same input data, then make input_data a member variable.
class A
{
public:
A(void * input_data)
{
set_input_data(input_data);
}
//Note, expensive operation
void set_input_data(void* input_data)
{
this->input_data = input_data;
fill_intermediate_buffer();
}
void foo() const;
void bar() const;
private:
void * input_data;
void * intermediate_buffer;
void * something;
};
This is just an outline obviously, without more details about what input_data, intermediate_buffer and something are or how they get used or shared a lot of details will be missing. I would definitely drop the pointers from the implementation and use std::vector. This is especially true of input_data, where you would want to store a copy of the passed-in buffer. Consider:
A a(input);
//modifiy input
a.foo();
You will likely get the wrong result from using a mismatched input_data/intermediate_buffer pair.
Also note that if you don't actually need input_data for foo and bar then you can drop the void* input_data from the class, but still keep the constructor and setter that refer to it.
I'd say that your use of mutable does make some amount of sense - but that it is incorrect, and possibly dangerous. If you make a function const it needs to be just that.
Imagine if you use your class in a multithreaded program, with several threads operating on the same instance of the class - for example:
thread1:
while(1) {
(...) //do some work
sharedA->foo(thread1Data);
sharedA->bar(thread1Data, true);
(...) //do some more work
sharedA->bar(thread1Data, true);
(...) //do even more work
}
thread2:
while(1) {
(...) //do some different work, maybe wait for an event
sharedA->foo(thread2Data);
(...) //sleep for a bit
}
Since thread2 is calling a const function, it shouldn't have any influence at all on the output of calling bar from thread1 - but if the timing is right (or wrong!) it will - and due to those reasons I'd say it's wrong to use mutable to make foo const in this case, even if you're only using the class from a single thread.
Given that you can't check input_data for equivalence, you could perhaps take a cryptographic hash of it and use that for the comparison. This would eliminate the need for the reuse_intermediate flag.
mutable is used to override the const-ness of a variable or data member.
Example:
Class A
{
public:
int m;
}
void foo(const A& a);
In the example above, function foo would be allowed to modify a.m even though you pass a const reference.
In your example I don't think you need to use mutable - it can lead to very bad designs - since you will write to that buffer.
In defining a function in an interface :
virtual void ModifyPreComputedCoeffs ( std::vector < IndexCoeffPair_t > & model_ ) = 0;
we want to specify that the vector model_ should not be altered in the sense push_back etc operations should not be done on the vector, but the IndexCoeffPair_t struct objects in the model_ could be changed.
How should we specify that ?
virtual void ModifyPreComputedCoeffs ( const std::vector < IndexCoeffPair_t > & model_ ) = 0;
does not work I think.
Rather than passing the vector into the function, do what the standard library does and pass a pair of iterators instead.
virtual void ModifyPreComputedCoeffs ( std::vector < IndexCoeffPair_t >::iterator & model_begin, std::vector < IndexCoeffPair_t >::iterator & model_end )
The C++ const-correctness concept is IMO way overrated. What you just discovered is one of the big limitations it has: it doesn't scale by composition.
To be able to create a const vector of non-const objects you need to implement your own vector type. Note that for example even the standard library had to introduce new types for const_iterators.
My suggestion is to use const-correctness where you are forced to, and not everywhere you can. In theory const correctness should help programmers, but comes at a very high cost because of the syntax and is very primitive (just one bit, doesn't scale by composition, even requires code duplication).
Also in my experience this alleged big help is not really that big... most of the errors it catches are related to the const-correctness machinery itself and not to program logic.
Ever wondered why most languages (including ones designed after C++) didn't implement this idea?
This is likely to be in C++14 as std::dynarray.
Actually if the size is fixed at compile time you can use std::array. But it's probably more use for things like embedded programming, buffers, matrices and so on as often you don't know the desired size until runtime or you want it to be configurable.
If you are able to modify IndexCoeffPair_t, you could add some const member functions and use them to change some of its members by making the members mutable using the mutable keyword. This is kind of a hack though, since you would now be able to change the contents of any const IndexCoeffPair_t.
Example:
class IndexCoeffPair_t {
public:
void changeX(int newVal) const {
x = newVal;
}
private:
mutable int x;
};
Here's a generic version of MahlerFive's answer:
template<typename T>
class Mutable {
mutable T m_val;
public:
constexpr Mutable(T const& val) : m_val(val) { }
constexpr Mutable(T&& val) : m_val(val) { }
// note: all member functions are `const`
constexpr Mutable const& operator=(T const& val) const {
m_val = val;
return *this;
}
constexpr Mutable const& operator=(T&& val) const {
m_val = val;
return *this;
}
constexpr operator T&() const {
return m_val;
}
};
You can then use std::vector<Mutable<T>> const in your code, which will mostly behave as intended.
You can try to create const std::vector<YouType*>. Then you can't change the vector but you can change objects inside vector.
But be accurate because you will modify original objects not copies.
Use smart pointers or raw pointers depends on your use cases: you have owning vector or just vector of observers.
Given a class like this:
class Foo
{
const int a;
};
Is it possible to put that class in a vector? When I try, my compiler tells me it can't use the default assignment operator. I try to write my own, but googling around tells me that it's impossible to write an assignment operator for a class with const data members. One post I found said that "if you made [the data member] const that means you don't want assignment to happen in the first place." This makes sense. I've written a class with const data members, and I never intended on using assignment on it, but apparently I need assignment to put it in a vector. Is there a way around this that still preserves const-correctness?
I've written a class with const data members, and I never intended on using assignment on it, but apparently I need assignment to put it in a vector. Is there a way around this that still preserves const-correctness?
You have to ask whether the following constraint still holds
a = b;
/* a is now equivalent to b */
If this constraint is not true for a and b being of type Foo (you have to define the semantics of what "equivalent" means!), then you just cannot put Foo into a Standard container. For example, auto_ptr cannot be put into Standard containers because it violates that requirement.
If you can say about your type that it satisfies this constraint (for example if the const member does not in any way participate to the value of your object, but then consider making it a static data member anyway), then you can write your own assignment operator
class Foo
{
const int a;
public:
Foo &operator=(Foo const& f) {
/* don't assign to "a" */
return *this;
}
};
But think twice!. To me, it looks like that your type does not satisfy the constraint!
Use a vector of pointers std::vector<Foo *>. If you want to avoid the hassle of cleaning up after yourself, use boost::ptr_vector.
Edit: My initial stab during my coffee break, static const int a; won't work for the use case the OP has in mind, which the initial comments confirm, so I'm rewriting and expanding my answer.
Most of the time, when I want to make an element of a class constant, it's a constant whose value is constant for all time and across all instances of the class. In that case, I use a static const variable:
class Foo
{
public:
static const int a;
};
Those don't need to be copied among instances, so if it applied, that would fix your assignment problem. Unfortunately, the OP has indicated that this won't work for the case the OP has in mind.
If you want to create a read-only value that clients can't modify, you can make it a private member variable and only expose it via a const getter method, as another post on this thread indicates:
class Foo
{
public:
int get_a() const { return a; }
private:
int a;
};
The difference between this and
class Foo
{
public:
const int a;
};
is:
The const int gives you assurance that not even the implementation of the class will be able to muck with the value of a during the lifetime of the object. This means that assignment rightfully won't work, since that would be trying to modify the value of a after the object's been created. (This is why, btw, writing a custom operator=() that skips the copy of a is probably a bad idea design-wise.)
The access is different – you have to go through a getter rather than accessing the member directly.
In practice, when choosing between the two, I use read-only members. Doing so probably means you'll be able to replace the value of an object with the value of another object without violating semantics at all. Let's see how it would work in your case.
Consider your Grid object, with a width and height. When you initially create the vector, and let's say you reserve some initial space using vector::reserve(), your vector will be populated with initial default-initialized (i.e. empty) Grids. When you go to assign to a particular position in the vector, or push a Grid onto the end of the vector, you replace the value of the object at that position with a Grid that has actual stuff. But you may be OK with this! If the reason you wanted width and height to be constant is really to ensure consistency between width and height and the rest of the contents of your Grid object, and you've verified that it doesn't matter whether width and height are replaced before or after other elements of Grid are replaced, then this assignment should be safe because by the end of the assignment, the entire contents of the instance will have been replaced and you'll be back in a consistent state. (If the lack of atomicity of the default assignment was a problem, you could probably get around this by implementing your own assignment operator which used a copy constructor and a swap() operation.)
In summary, what you gain by using read-only getters is the ability to use the objects in a vector or any container with value semantics. However, it then falls to you to ensure that none of Grid's internal operations (or the operations of friends of Grid) violate this consistency, because the compiler won't be locking down the width and height for you. This goes for default construction, copy construction, and assignment as well.
I'm considering making the data member non-const, but private and only accessible by a get function, like this:
class Foo
{
private:
int a;
public:
int getA() const {return a;}
};
Is this 'as good' as const? Does it have any disadvantages?
As of c++20, using const member variables are legal without restrictions that had made it virtually unusable in containers. You still have to define a copy assignment member function because it continues to be automatically deleted when a const object exists in the class. However, changes to "basic.life" now allow changing const sub-objects and c++ provides rather convenient functions for doing this. Here's a description of why the change was made:
The following code shows how to define a copy assignment member function which is useable in any class containing const member objects and uses the new functions std::destroy_at and std::construct_at to fulfil the requirement so the new "basic.life" rules. The code demonstrates assignment of vectors as well as sorting vectors with const elements.
Compiler explorer using MSVC, GCC, CLANG https://godbolt.org/z/McfcaMWqj
#include <memory>
#include <vector>
#include <iostream>
#include <algorithm>
class Foo
{
public:
const int a;
Foo& operator=(const Foo& arg) {
if (this != &arg)
{
std::destroy_at(this);
std::construct_at(this, arg);
}
return *this;
}
};
int main()
{
std::vector<Foo> v;
v.push_back({ 2 });
v.push_back({ 1 });
v.insert(v.begin() + 1, Foo{ 0 });
std::vector<Foo> v2;
v2 = v;
std::sort(v2.begin(), v2.end(), [](auto p1, auto p2) {return p1.a < p2.a; });
for (auto& x : v2)
std::cout << x.a << '\n';
}
I want to implement a Swap() method for my class (let's call it A) to make copy-and-swap operator=(). As far as I know, swap method should be implemented by swapping all members of the class, for example:
class A
{
public:
void swap(A& rhv)
{
std::swap(x, rhv.x);
std::swap(y, rhv.y);
std::swap(z, rhv.z);
}
private:
int x,y,z;
};
But what should I do if I have a const member? I can't call std::swap for it, so I can't code A::Swap().
EDIT: Actually my class is little bit more complicated. I want to Serialize and Deserialize it. Const member is a piece of data that won't change (its ID for example) within this object. So I was thinking of writing something like:
class A
{
public:
void Serialize(FILE* file) const
{
fwrite(&read_a, 1, sizeof(read_a), file);
}
void Deserialize(FILE* file) const
{
size_t read_a;
fread(&read_a, 1, sizeof(read_a), file);
A tmp(read_a);
this->Swap(tmp);
}
private:
const size_t a;
};
and call this code:
A a;
FILE* f = fopen(...);
a.Deserialize(f);
I'm sorry for such vague wording.
I think what you really want is to have an internal data structure that you can easily exchange between objects. For example:
class A
{
private:
struct A_Data {
int x;
int y;
const int z;
A_Data(int initial_z) : z(initial_z) {}
};
std::auto_ptr<A_Data> p_data;
public:
A(int initial_z) : p_data(new A_Data(initial_z)) {}
void swap(A& rhv) {
std::swap(p_data, rhv.p_data);
}
};
This keeps the z value constant within any instance of A object internal data, but you can swap the internal data of two A objects (including the constant z value) without violating const-correctness.
After a good nights sleep I think the best answer is to use a non-const pointer to a const value -- after all these are the semantics you are trying to capture.
f0b0s, a good design principle is to design your objects to be immutable. This means that the object can't change once created. To "change" the object, you must copy the object and make sure to change the elements you want.
That being said, in this case you should look at using a copy constructor instead to copy the objects you want to swap, and then actually swap the references to the object. I can understand it'd be tempting just to be able to change the elements of an object under the hood, but it'd be better to make a copy of the object and replace the references to that object with the NEW object instead. This gets you around any const nastiness.
Hope this helps.
I suggest you use pointers to the instances. The pointers can be swapped much easier than the data in the class or struct.
The only way to swap a constant value is to create another object, or clone the current object.
Given a struct:
struct My_Struct
{
const unsigned int ID;
std::string name;
My_Struct(unsigned int new_id)
: ID(new_id)
{ ; }
};
My understanding is that you want to swap instances of something like My_Struct above. You can copy the mutable (non-const) members but not the const member. The only method to alter the const member is to create a new instance with a new value for the const member.
Perhaps you need to rethink your design.
IMHO you must consider not to swap CONST members.
PD: I think you could consider to use reflection in your approach. so you don't have to maintain the function.
This is why const_cast was created. Just remember not to shoot your foot off.
Edit: OK, I concede - const_cast wasn't made for this problem at all. This might work with your compiler, but you can't count on it and if demons come flying out of your nostrils, please don't blame me.
tl;dr; : It's Undefined Behavior.
Reference/reason: CppCon 2017: Scott Schurr “Type Punning in C++17: Avoiding Pun-defined Behavior, #24m52s +- ”
My interpretation, by example:
Suppose you create an object of type T, which have some const members. You can pass this object as a non-const reference to a function f(&T) that manipulates it, but you'd expect the const members to remain unalterable after the call. swap can be called in non-const references, and it can happen inside the function f, breaking the premise of const members to the caller.
Every part of your code that uses swap would have to assert that the object of type T being swapped does not belong to any context where the const members are assumed constant. That is impossible to automatically verify*.
*I just assumed that this is impossible to verify because it seems like an extension of the undecidability of the halting problem.