Without relying on const_cast, how can one make a C++ data member const after but not during construction when there is an expensive-to-compute intermediate value that is needed to calculate multiple data members?
The following minimal, complete, verifiable example further explains the question and its reason. To avoid wasting your time, I recommend that you begin by reading the example's two comments.
#include <iostream>
namespace {
constexpr int initializer {3};
constexpr int ka {10};
constexpr int kb {25};
class T {
private:
int value;
const int a_;
const int b_;
public:
T(int n);
inline int operator()() const { return value; }
inline int a() const { return a_; }
inline int b() const { return b_; }
int &operator--();
};
T::T(const int n): value {n - 1}, a_ {0}, b_ {0}
{
// The integer expensive
// + is to be computed only once and,
// + after the T object has been constructed,
// is not to be stored.
// These requirements must be met without reliance
// on the compiler's optimizer.
const int expensive {n*n*n - 1};
const_cast<int &>(a_) = ka*expensive;
const_cast<int &>(b_) = kb*expensive;
}
int &T::operator--()
{
--value;
// To alter a_ or b_ is forbidden. Therefore, the compiler
// must abort compilation if the next line is uncommented.
//--a_; --b_;
return value;
}
}
int main()
{
T t(initializer);
std::cout << "before decrement, t() == " << t() << "\n";
--t;
std::cout << "after decrement, t() == " << t() << "\n";
std::cout << "t.a() == " << t.a() << "\n";
std::cout << "t.b() == " << t.b() << "\n";
return 0;
}
Output:
before decrement, t() == 2
after decrement, t() == 1
t.a() == 260
t.b() == 650
(I am aware of this previous, beginner's question, but it treats an elementary case. Please see my comments in the code above. My trouble is that I have an expensive initialization I do not wish to perform twice, whose intermediate result I do not wish to store; whereas I still wish the compiler to protect my constant data members once construction is complete. I realize that some C++ programmers avoid constant data members on principle but this is a matter of style. I am not asking how to avoid constant data members; I am asking how to implement them in such a case as mine without resort to const_cast and without wasting memory, execution time, or runtime battery charge.)
FOLLOW-UP
After reading the several answers and experimenting on my PC, I believe that I have taken the wrong approach and, therefore, asked the wrong question. Though C++ does afford const data members, their use tends to run contrary to normal data paradigms. What is a const data member of a variable object, after all? It isn't really constant in the usual sense, is it, for one can overwrite it by using the = operator on its parent object. It is awkward. It does not suit its intended purpose.
#Homer512's comment illustrates the trouble with my approach:
Don't overstress yourself into making members const when it is inconvenient. If anything, it can lead to inefficient code generation, e.g. by making move-construction fall back to copy constructions.
The right way to prevent inadvertent modification to data members that should not change is apparently, simply to provide no interface to change them—and if it is necessary to protect the data members from the class's own member functions, why, #Some programmer dude's answer shows how to do this.
I now doubt that it is possible to handle const data members smoothly in C++. The const is protecting the wrong thing in this case.
Something along these lines perhaps:
class T {
private:
T(int n, int expensive)
: value{n-1}, a_{ka*expensive}, b_{kb*expensive} {}
public:
T(int n) : T(n, n*n*n - 1) {}
};
One possible way could be to put a and b in a second structure, which does the expensive calculation, and then have a constant member of this structure.
Perhaps something like this:
class T {
struct constants {
int a;
int b;
constants(int n) {
const int expensive = ... something involving n...;
a = ka * expensive;
b = kb * expensive;
}
};
constants const c_;
public:
T(int n)
: c_{ n }
{
}
};
With that said, why make a_ and b_ constant in the first place, if you control the class T and its implementation?
If you want to inhibit possible modifications from other developers that might work on the T class, then add plenty of documentation and comments about the values not being allowed to be modified. Then if someone modifies the values of a_ or b_ anyway, then it's their fault for making possibly breaking changes. Good code-review practices and proper version control handling should then be used to point out and possibly blame wrongdoers.
Before describing the answer, I'd first suggest you to re-think your interface. If there's an expensive operation, why don't you let the caller be aware of it and allow them to cache the result? Usually the design forms around the calculations and abstractions that are worth keeping as a state; if it's expensive and reusable, it's definitely worth keeping.
Therefore, I'd suggest to put this to the public interface:
struct ExpensiveResult
{
int expensive;
ExpensiveResult(int n)
: expensive(n*n*n - 1)
{}
};
class T
{
private:
const int a;
const int b;
T(const ExpensiveResult& e)
: a(ka * e.expensive)
, b(kb * e.expensive)
{}
};
Note that ExpensiveResult can be directly constructed from int n (ctor is not explicit), therefore call syntax is similar when you don't cache it; but, caller might, at any time, start storing the result of the expensive calculation.
It's pretty easy to modify the const ints in your object as a result of a significant change in c++20. The library function construct_at and destroy_at have been provided to simplify this. For your class, destroy_at is superfluous since the class contains no members that use dynamic memory like vector, etc. I've made a small modification, added a constructor taking just an int. Also defined an operator= which allows the objects to be manipulated in containers. You can also use construct_at to decrement a_ and b_ in your operator-- method. Here's the code:
#include <iostream>
#include <memory>
namespace {
constexpr int initializer{ 3 };
constexpr int ka{ 10 };
constexpr int kb{ 25 };
class T {
private:
int value;
const int a_{};
const int b_{};
public:
T(int n);
T(int n, int a, int b);
T(const T&) = default;
inline int operator()() const { return value; }
inline int a() const { return a_; }
inline int b() const { return b_; }
int& operator--();
T& operator=(const T& arg) { std::construct_at(this, arg); return *this; };
};
T::T(const int n, const int a, const int b) : value{ n - 1 }, a_{ a }, b_{ b } {}
T::T(const int n) : value{ n - 1 }
{
// The integer expensive
// + is to be computed only once and,
// + after the T object has been constructed,
// is not to be stored.
// These requirements must be met without reliance
// on the compiler's optimizer.
const int expensive{ n * n * n - 1 };
std::construct_at(this, n, ka*expensive, kb*expensive);
}
int& T::operator--()
{
// implement decrements
//--a_; --b_;
const int a_1 = a_ - 1;
const int b_1 = b_ - 1;
std::construct_at(this, value, a_1, b_1);
return value;
}
}
int main()
{
T t(initializer);
std::cout << "before decrement, t() == " << t() << "\n";
--t;
std::cout << "after decrement, t() == " << t() << "\n";
std::cout << "t.a() == " << t.a() << "\n";
std::cout << "t.b() == " << t.b() << "\n";
return 0;
}
Output:
before decrement, t() == 2
after decrement, t() == 1
t.a() == 259
t.b() == 649
Related
I'm trying to implement Natural numbers with C++, here's the code I have so far (O() is the 0 (zero) number and S(Nat) is the successor function).
// Peano arithmetic C++
// Null element
struct O{
explicit operator const unsigned int() const { return 0; }
};
// Successor function
struct S {
unsigned int val;
explicit operator const unsigned int() const {
// Boundary check
std::cout << "Incremented once" << std::endl;
if (this->val < UINT_MAX) {
return this->val + 1;
}
// Don't wrap around, hit the ceiling and stay there
return this->val;
}
S(const unsigned int a) {
this->val = a;
}
// Constructor
S(const O& zero) {
this->val = 0;
}
S(const S& s) {
this->val = static_cast<const unsigned int>(s);
}
};
// Nat
using Nat = std::variant<O, S>;
int main() {
std::cout << static_cast<const unsigned int>(S(O())) << std::endl;
std::cout << static_cast<const unsigned int>(S(S(O()))) << std::endl;
return 0;
}
What I expected was the static_cast to unsigned to give me 1, 2. What I get is actually 1, 1!
S(const S& s) is a copy constructor, and the compiler is allowed to elide calls to the copy constructor in certain cases. This is an optional optimization in C++14 and below, and required in C++17. You can verify that this happens here by putting a print statement inside this constructor, which won't print anything.
In this case, it will make the expression S(S(O())) equivalent to S(O()).
Therefore, this way of doing things won't work here. You can make S a function instead, which can return either an integer (making it trivial), or some object if you prefer to keep things similar to your code here.
I have a non-virtual class template A as below and I do the following
#include <iostream>
// my class template
template<typename T>
class A
{
public:
T x;
T y;
T z;
// bunch of other non-virtual member functions including constructors, etc
// and obviously no user-defined destructor
// ...
};
int main()
{
//now I do the following
A<double> a;
a.x = 1.0; // not important this
a.y = 2.0;
a.z = 3.0;
// now the concerned thing
double* ap = (double*)&a;
double* xp = &(a.x);
// can I correctly and meaningfully do the following?
double new_az = ap[2]; // guaranteed to be same as a.z (for any z) ? ** look here **
double new_z = xp[2]; // guaranteed to be same as a.z (for any z) ? ** look here **
std::cout<<new_az<<std::endl;
std::cout<<new_z<<std::endl;
return 0;
}
So, is it guaranteed that if I use a raw point to object A or to the member variable a.x, I will correctly get the other variables?
As many users pointed out, there is no guarantee that the memory layout of your structure will be identical to the appropriate array. And "ideologically correct" way to access members by index would be creating some ugly operator [] with a switch inside it.
However, speaking practically, there is usually no problem with your approach, and the suggested solutions are inferior in terms of code generated and run-time performance.
I can suggest 2 other solutions.
Keep your solution, but verify in compile-time that your structure layout corresponds to an array. In your specific case putting STATIC_ASSERT(sizeof(a) == sizeof(double)*3);
Change your template class to be actually an array, and convert the x,y,zvariables into the access functions into the elements of the array.
I mean:
#include <iostream>
// my class template
template<typename T>
class A
{
public:
T m_Array[3];
T& x() { return m_Array[0]; }
const T& x() const { return m_Array[0]; }
// repeat for y,z
// ...
};
If you make the length of the array (i.e. dimension of the represented vector) a template parameter as well, you may put a 'STATIC_ASSERT' in each access function to ensure the actual existence of the member.
No, there is no guarantee, not the way you do it. If T is a int8_t, for example, it would work only if you specified 1-byte packing.
The easiest, and correct way to do this, would be to add an operator [] to your template class, something like:
T& operator[](size_t i)
{
switch(i)
{
case 0: return x;
case 1: return y;
case 2: return z:
}
throw std::out_of_range(__FUNCTION__);
}
const T& operator[](size_t i) const
{
return (*const_cast<A*>(this))[i]; // not everyone likes to do this.
}
But this is not really efficient. A more efficient way is to have your vector (or point) coordinates in a array, and x(), y(), z() member functions to access them. Then you example would work in all cases, provided you implement a T* operator in your class.
operator T*() { return &values[0]; }
operator const T*()const { return &values[0]; }
If you really want to do such things:
template <typename T>
class FieldIteratable
{
using Data = std::array<T, 5/*magic number*/>;
Data data_;
public:
const Data & data() { return data_; }
T& a1 = data_[0]; // or some macro
char padding1[3]; // you can choose what field is iteratable
T& a2 = data_[1];
char padding2[3]; // class can contain other fields can be
T& a3 = data_[2];
char padding3[3];
T& a4 = data_[3];
char padding4[3];
T& a5 = data_[4];
};
int main() {
FieldIteratable<int> fi;
int* a = &fi.a1;
*a++ = 0;
*a++ = 1;
*a++ = 2;
*a++ = 3;
*a++ = 4;
std::cout << fi.a1 << std::endl;
std::cout << fi.a2 << std::endl;
std::cout << fi.a3 << std::endl;
std::cout << fi.a4 << std::endl;
std::cout << fi.a5 << std::endl;
for(auto i :fi.data())
std::cout << i << std::endl;
return 0;
}
I would like to know if copying an object in the following manner is acceptable vis-a-vis copying the individual elements.
#include <iostream>
using namespace std;
class abc{
public:
abc(int a = 10, int b = 5);
abc(const abc &obj, int b = 10);
int ret_x() { return x; }
int ret_y() { return y; }
private:
int x;
int y;
};
abc::abc(int a, int b)
: x(a),
y(b)
{
}
abc::abc(const abc &obj, int b)
{
if (this != &obj) {
*this = obj; -----> Copying the object
}
y = b;
}
int main()
{
abc a1;
cout << "A1 values: " << a1.ret_x() << "\t" << a1.ret_y() << endl;
abc a2(a1, 20);
cout << "A2 values: " << a2.ret_x() << "\t" << a2.ret_y() << endl;
return 0;
}
Edit:
Use case:
The issue is that object a1 is auto-generated and hence any newly introduced members in the class could not be updated. I could provide a member function to update the new members, sure, but wanted to explore this option.
The code works fine, but is the method correct?
Thanks!
As chris noted already in the comments, you are creating a completely new object. How would you want to get this passed into the constructor? Well, actually, you could perhaps via placement new:
abc a;
abc* b = new(&a)abc(a);
But this is a such an exotic case that I would not consider it, I even dare to claim someone using advanced stuff such as placement new should know what he is doing... So leave out the if-check.
In your special case, it seems OK, as no data exists that might require deep copying. Be aware, though, that you are assigning the member b twice. Not really critical with int, but on larger objects (std::string, std::vector, ...) which do deep copies this gets more and more questionable.
With C++11, though, I would prefer constructor delegation:
abc::abc(const abc& obj, int b)
: abc(obj) // copying here
{
y = b;
}
This does not solve, however, the double assignment problem. To be honest, this might not always be a true problem, in many cases the compiler might optimise the first assignment away (especially in the int case of our example). But on more complex data types (possibly already std::string), I wouldn't feel comfortable relying on the compiler detecting obsolete assignment...
Be aware that you might get into trouble if you have resources managed internally:
struct abc
{
int* array;
abc() : array(new int[7]) { }
~abc()
{
delete[] array;
}
}
Not providing an appropriate assignment operator or copy constructor – depending on the implementation variant, yours (assignment) or mine (constructor delegation) – doing the necessary deep copy will result in multiple deletion of the same data (undefined behaviour!). Following the rule of three (or more recently, rule of five), you most probably will need both anyway. You might consider the copy and swap idiom idiom then.
Finally a trick to avoid double assignment:
abc(abc const& other)
: abc(other, other.y)
{ }
abc(abc const& other, int y)
: x(other.x), y(y)
{ }
In the comments to this answer, Koushik raised a very valid point.
Take the following:
union U
{
int x;
const T y;
};
(I choose T such that there is no common initial sequence of layout compatibility here, meaning only one member may be active at any given time per [C++11: 9.5/1].)
Since only one member may be "active" at any one time (made active by writing to it), and y cannot be written to after initialisation, isn't this rather pointless? I mean, y can only be read from until the first time x is written to, and at that only if y was the initialised member.
Is there some use case I'm missing? Or is this indeed a pretty pointless confluence of language features?
(This has been mentioned before)
Here's a contrived example of a reference-semantics type where you'd only want to grant const access to. The union is used in a variant-like data type returned from a "type-erasing" function.
#include <memory>
template<class T>
struct reference_semantics
{
public:
reference_semantics(T* p ) : m(p) {}
int observe() const { return *m; }
void change(T p) { *m = p; }
private:
T* m;
};
struct variant
{
enum T { INT, DOUBLE } type;
union U
{
reference_semantics<int> const i;
reference_semantics<double> const d;
U(int* p) : i(p) {}
U(double* p) : d(p) {}
} u;
};
#include <iostream>
std::ostream& operator<<(std::ostream& o, variant const& v)
{
switch(v.type)
{
case variant::INT:
return o << "INT: "<<v.u.i.observe();
case variant::DOUBLE:
return o << "DOUBLE: "<<v.u.d.observe();
}
}
#include <string>
variant type_erased_access(std::string name)
{
// imagine accesses to a map or so
static double dval = 42.21;
static int ival = 1729;
if(name == "Lightness") return { variant::DOUBLE, &dval };
else return { variant::INT, &ival };
}
int main()
{
variant v0( type_erased_access("Lightness") );
std::cout << v0 << "\n";
variant v1( type_erased_access("Darkness") );
std::cout << v1 << "\n";
}
Imagine now that instead of int and double, much larger data types are used, and that the reference_semantics data type actually provides more functionality than just returning the value.
It might even be possible that you want to return a reference_semantics<some_type> const for some arguments, but a plain int for others. In that case, your union might even have const and non-const members.
It does have uses:
1) For offering a const_cast-like technique. In a sense, x = const_cast<...>(y).
2) When dealing with templates, sometimes you need a const version of a data type so you match other parameter types.
(I've seen (1) used when programming against legacy interfaces).
Not using unions a lot, but this might be scenario:
#include <iostream>
class Accessor;
union Union
{
private:
friend class Accessor;
int write;
public:
const int read;
Union() : read(0) {}
};
class Accessor {
public:
static void apply(Union& u, int i) { u.write = i; }
};
int main() {
Union u;
// error: ‘int Union::write’ is private
// u.write = 1;
std::cout << u.read << '\n';
Accessor::apply(u, 1);
std::cout << u.read << '\n';
}
Note: From 9.5 Unions
Note: One special guarantee is made in order to simplify the use of
unions: If a standard-layout union contains several standard-layout
structs that share a common initial sequence (9.2), and if an object
of this standard-layout union type contains one of the standard-layout
structs, it is permitted to inspect the common initial sequence of any
of standard-layout struct members; see 9.2. — end note ]
If the union represents part of a result of some method/algorithm, then it could make sense. But in that case, I'd make both values const:
union T
{
const int x;
const int y;
};
Is there a way to make a non-resizeable vector/array of non-reassignable but mutable members? The closest thing I can imagine is using a vector<T *> const copy constructed from a temporary, but since I know at initialization how many of and exactly what I want, I'd much rather have a block of objects than pointers. Is anything like what is shown below possible with std::vector or some more obscure boost, etc., template?
// Struct making vec<A> that cannot be resized or have contents reassigned.
struct B {
vector<A> va_; // <-- unknown modifiers or different template needed here
vector<A> va2_;
// All vector contents initialized on construction.
Foo(size_t n_foo) : va_(n_foo), va2_(5) { }
// Things I'd like allowed: altering contents, const_iterator and read access.
good_actions(size_t idx, int val) {
va_[idx].set(val);
cout << "vector<A> info - " << " size: " << va_.size() << ", max: "
<< va_.max_size() << ", capacity: " << va_.capacity() << ", empty?: "
<< va_.empty() << endl;
if (!va_.empty()) {
cout << "First (old): " << va_[0].get() << ", resetting ..." << endl;
va_[0].set(0);
}
int max = 0;
for (vector<A>::const_iterator i = va_.begin(); i != va_.end(); ++i) {
int n = i->get();
if (n > max) { max = n; }
if (n < 0) { i->set(0); }
}
cout << "Max : " << max << "." << endl;
}
// Everything here should fail at compile.
bad_actions(size_t idx, int val) {
va_[0] = va2_[0];
va_.at(1) = va2_.at(3);
va_.swap(va2_);
va_.erase(va_.begin());
va_.insert(va_.end(), va2_[0]);
va_.resize(1);
va_.clear();
// also: assign, reserve, push, pop, ..
}
};
There is an issue with your requirements. But first let's tackle the fixed size issue, it's called std::tr1::array<class T, size_t N> (if you know the size at compile time).
If you don't know it at compile time, you can still use some proxy class over a vector.
template <class T>
class MyVector
{
public:
explicit MyVector(size_t const n, T const& t = T()): mVector(n,t) {}
// Declare the methods you want here
// and just forward to mVector most of the time ;)
private:
std::vector<T> mVector;
};
However, what is the point of not being assignable if you are mutable ? There is nothing preventing the user to do the heavy work:
class Type
{
public:
int a() const { return a; }
void a(int i) { a = i; }
int b() const { return b; }
void b(int i) { b = i; }
private:
Type& operator=(Type const&);
int a, b;
};
Nothing prevents me from doing:
void assign(Type& lhs, Type const& rhs)
{
lhs.a(rhs.a());
lhs.b(rhs.b());
}
I just want to hit you on the head for complicating my life...
Perhaps could you describe more precisely what you want to do, do you wish to restrict the subset of possible operations on your class (some variables should not be possible to modify, but other could) ?
In this case, you could once again use a Proxy class
class Proxy
{
public:
// WARN: syntax is screwed, but `vector` requires a model
// of the Assignable concept so this operation NEED be defined...
Proxy& operator=(Proxy const& rhs)
{
mType.a = rhs.mType.a;
// mType.b is unchanged
return *this;
}
int a() const { return mType.a(); }
void a(int i) { mType.a(i); }
int b() const { return mType.b(); }
private:
Type mType;
};
There is not much you cannot do with suitable proxies. That's perhaps the most useful pattern I have ever seen.
What you're asking is not really possible.
The only way to prevent something from being assigned is to define the operator = for that type as private. (As an extension of this, since const operator = methods don't make much sense (and are thus uncommon) you can come close to this by only allowing access to const references from your container. But the user can still define a const operator =, and you want mutable objects anyways.)
If you think about it, std::vector::operator [] returns a reference to the value it contains. Using the assignment operator will call operator = for the value. std::vector is completely bypassed here (except for the operator[] call used to get the reference in the first place) so there is no possibility for it (std::vector) to in any way to override the call to the operator = function.
Anything you do to directly access the members of an object in the container is going to have to return a reference to the object, which can then be used to call the object's operator =. So, there is no way a container can prevent objects inside of it from being assigned unless the container implements a proxy for the objects it contains which has a private assignment operator that does nothing and forwards other calls to the "real" object, but does not allow direct access to the real object (though if it made sense to do so, you could return copies of the real object).
Could you create a class which holds a reference to your object, but its constructors are only accessible to its std::vector's friend?
e.g.:
template<typename T>
class MyRef {
firend class std::vector< MyRef<T> >
public:
T& operator->();
[...etc...]
You can achieve what you want by making the std::vector const, and the vector's struct or class data mutable. Your set method would have to be const. Here's an example that works as expected with g++:
#include <vector>
class foo
{
public:
foo () : n_ () {}
void set(int n) const { n_ = n; }
private:
mutable int n_;
};
int main()
{
std::vector<foo> const a(3); // Notice the "const".
std::vector<foo> b(1);
// Executes!
a[0].set(1);
// Failes to compile!
a.swap(b);
}
That way you can't alter the vector in any way but you can modify the mutable data members of the objects held by the vector. Here's how this example compiles:
g++ foo.cpp
foo.cpp: In function 'int main()':
foo.cpp:24: error: passing 'const std::vector<foo, std::allocator<foo> >' as 'this' argument of 'void std::vector<_Tp, _Alloc>::swap(std::vector<_Tp, _Alloc>&) [with _Tp = foo, _Alloc = std::allocator<foo>]' discards qualifiers
The one disadvantage I can think of is that you'll have to be more aware of the const-correctness of your code, but that's not necessarily a disadvantage either.
HTH!
EDIT / Clarification: The goal of this approach is not defeat const completely. Rather, the goal is to demonstrate a means of achieving the requirements set forth in the OP's question using standard C++ and the STL. It is not the ideal solution since it exposes a const method that allows alteration of the internal state visible to the user. Certainly that is a problem with this approach.