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.
Related
I'm implementing a two-dimensional array container (like boost::multi_array<T,2>, mostly for practice). In order to use double-index notation (a[i][j]), I introduced a proxy class row_view (and const_row_view but I'm not concerned about constness here) which keeps a pointer to the beginning and end of the row.
I would also like to be able to iterate over rows and over elements within a row separately:
matrix<double> m;
// fill m
for (row_view row : m) {
for (double& elem : row) {
// do something with elem
}
}
Now, the matrix<T>::iterator class (which is meant to iterate over rows) keeps a private row_view rv; internally to keep track of the row the iterator is pointing to. Naturally, iterator also implements dereferenciation functions:
for operator*(), one would usually want to return a reference. Instead, here the right thing to do seems to return a row_view by value (i.e. return a copy of the private row_view). This ensures that when the iterator is advanced, the row_view still points to the previous row. (In a way, row_view acts like a reference would).
for operator->(), I'm not so sure. I see two options:
Return a pointer to the private row_view of the iterator:
row_view* operator->() const { return &rv; }
Return a pointer to a new row_view (a copy of the private one). Because of storage lifetime, that would have to be allocated on the heap. In order to ensure clean-up, I'd wrap it in a unique_ptr:
std::unique_ptr<row_view> operator->() const {
return std::unique_ptr<row_view>(new row_view(rv));
}
Obviously, 2 is more correct. If the iterator is advanced after operator-> is called, the row_view that is pointed to in 1 will change. However, the only way I can think of where this would matter, is if the operator-> was called by its full name and the returned pointer was bound:
matrix<double>::iterator it = m.begin();
row_view* row_ptr = it.operator->();
// row_ptr points to view to first row
++it;
// in version 1: row_ptr points to second row (unintended)
// in version 2: row_ptr still points to first row (intended)
However, this is not how you'd typically use operator->. In such a use case, you'd probably call operator* and keep a reference to the first row. Usually, one would immediately use the pointer to call a member function of row_view or access a member, e.g. it->sum().
My question now is this: Given that the -> syntax suggests immediate use, is the validity of the pointer returned by operator-> considered to be limited to that situation, or would a safe implementation account for the above "abuse"?
Obviously, solution 2 is way more expensive, as it requires heap-allocation. This is of course very much undesirable, as dereferenciation is quite a common task and there is no real need for it: using operator* instead avoids these problems as it returns a stack-allocated copy of the row_view.
As you know, operator-> is applied recursively on the functions return type until a raw pointer is encountered. The only exception is when it's called by name like in your code sample.
You can use that to your advantage and return a custom proxy object. To avoid the scenario in your last code snippet, this object needs to satisfy several requirements:
Its type name should be private to the matrix<>::iterator, so outside code could not refer to it.
Its construction/copy/assignment should be private. matrix<>::iterator will have access to those by virtue of being a friend.
An implementation will look somewhat like this:
template <...>
class matrix<...>::iterator {
private:
class row_proxy {
row_view *rv_;
friend class iterator;
row_proxy(row_view *rv) : rv_(rv) {}
row_proxy(row_proxy const&) = default;
row_proxy& operator=(row_proxy const&) = default;
public:
row_view* operator->() { return rv_; }
};
public:
row_proxy operator->() {
row_proxy ret(/*some row view*/);
return ret;
}
};
The implementation of operator-> returns a named object to avoid any loopholes due to guaranteed copy elision in C++17. Code that use the operator inline (it->mem) will work as before. However, any attempt to call operator->() by name without discarding the return value, will not compile.
Live Example
struct data {
int a;
int b;
} stat;
class iterator {
private:
class proxy {
data *d_;
friend class iterator;
proxy(data *d) : d_(d) {}
proxy(proxy const&) = default;
proxy& operator=(proxy const&) = default;
public:
data* operator->() { return d_; }
};
public:
proxy operator->() {
proxy ret(&stat);
return ret;
}
};
int main()
{
iterator i;
i->a = 3;
// All the following will not compile
// iterator::proxy p = i.operator->();
// auto p = i.operator->();
// auto p{i.operator->()};
}
Upon further review of my suggested solution, I realized that it's not quite as fool-proof as I thought. One cannot create an object of the proxy class outside the scope of iterator, but one can still bind a reference to it:
auto &&r = i.operator->();
auto *d = r.operator->();
Thus allowing to apply operator->() again.
The immediate solution is to qualify the operator of the proxy object, and make it applicable only to rvalues. Like so for my live example:
data* operator->() && { return d_; }
This will cause the two lines above to emit an error again, while the proper use of the iterator still works. Unfortunately, this still doesn't protect the API from abuse, due to the availability of casting, mainly:
auto &&r = i.operator->();
auto *d = std::move(r).operator->();
Which is a death blow to the whole endeavor. There is no preventing this.
So in conclusion, there is no protection from a direction call to operator-> on the iterator object. At the most, we can only make the API really hard to use incorrectly, while the correct usage remains easy.
If creation of row_view copies is expansive, this may be good enough. But that is for you to consider.
Another point for consideration, which I haven't touched on in this answer, is that the proxy could be used to implement copy on write. But that class could be just as vulnerable as the proxy in my answer, unless great care is taken and fairly conservative design is used.
I'm having some problems with the const_cast function. I created a class Calorimeter that consists of a CaloGrid and some other stuff. I have to overload the grid() function to return the CaloGrid belonging to the class Calorimeter, however calling the main function returns a segmentation fault.
I know that using const_cast is not the best practice, but for this assignment I have to use it. Simply duplicating the code for the const CaloGrid& grid() const for the non-constant function would probably work.
What am I doing wrong? Is there a better way of doing this? And what is the point of overloading the function with a const copy of the function?
main.cpp
/*headers*/
int main() {
// create 2x2 Calorimeter object
Calorimeter C(2,2);
// return the CaloGrid class from this object
C.grid();
// gives segmentation error
}
Calorimeter.cpp
/*headers*/
// Calorimeter is object with CaloGrid of dimensions nx by ny
Calorimeter::Calorimeter(int nx,int ny){
// initalize the grid and allocate memory
Cgrid = new CaloGrid(nx,ny);
}
Calorimeter::~Calorimeter(){
// delete memory
delete Cgrid;
}
// return the grid
const CaloGrid& Calorimeter::grid() const{
return *Cgrid;
}
// segmentation error
CaloGrid& Calorimeter::grid(){
return const_cast<CaloGrid&> (Calorimeter::grid());
}
Calorimeter.hh
#ifndef CALORIMETER_HH
#define CALORIMETER_HH
class Calorimeter {
public: // Interface
Calorimeter(int,int);
~Calorimeter();
const CaloGrid& grid() const;
CaloGrid& grid();
private: // Implementation
CaloGrid *Cgrid;
}
#endif
In
return const_cast<CaloGrid&> (Calorimeter::grid());
You are infinitly calling grid(). Since the grid function is non const Calorimeter::grid() will call the non const version of the function again, which calls the non const version again which, well, you get the point.
If you want to call the const version of the function then you need to cast this to const. You can do that with
const_cast<const Calorimeter&>(*this)
So with that your full code would look like
return const_cast<CaloGrid&>(const_cast<const Calorimeter&>(*this).grid());
If it doesn't look right it is probably the tears getting in your eyes from the code.
Here's your class method:
CaloGrid& Calorimeter::grid(){
What does it do? Well:
return const_cast<CaloGrid&> (Calorimeter::grid());
It calls Calorimeter::grid(), and applies const_cast to its return value? What does this Calorimeter::grid() do? See above.
The issue of what const_cast does, and whether or not it's the right thing to do is irrelevant. This class method calls itself, resulting in infinite recursion, and your program blows quickly, as it runs out of its operating system-allotted stack space.
Although it's not quite clear what you're trying to do here, the answer as to the reason of your segfault is quite simple: infinite recursion.
The recursive call does not invoke the other, overloaded, const class method. This is being called from a mutable class method, so it picks the mutable overload, again.
Expanding on the other posts, you may want to consider writing it this way:
#include <memory>
struct CaloGrid {
CaloGrid(int x, int y) {};
};
class Calorimeter {
public: // Interface
Calorimeter(int,int);
// no destructor - it's not necessary
const CaloGrid& grid() const;
CaloGrid& grid();
private: // Implementation
// resources managed automatically
std::unique_ptr<CaloGrid> Cgrid;
};
// Calorimeter is object with CaloGrid of dimensions nx by ny
Calorimeter::Calorimeter(int nx,int ny)
: Cgrid { std::make_unique<CaloGrid>(nx, ny) }
{
}
// return the grid
const CaloGrid& Calorimeter::grid() const{
return *Cgrid;
}
// no error any more
CaloGrid& Calorimeter::grid(){
return *Cgrid;
}
int main() {
// create 2x2 Calorimeter object
// now we can use move-construction
auto C = Calorimeter(2,2);
// return the CaloGrid class from this object
C.grid();
}
The raw pointer has been replaced with a smart pointer. This gives us (at least) 2 advantages:
Resource management is automated, so we can't forget to delete the CaloGrid, or accidentally delete it twice.
Calorimeter inherits the copy/move capabilities of the smart pointer (in this case, dangerous unwanted copies are disallowed but we get to keep moves and move-assignments)
Furthermore, although the grid method now repeats code, it repeats trivial code. The class has become much easier to both use correctly and maintain.
What you need is the following
CaloGrid & Calorimeter::grid()
{
return const_cast<CaloGrid &>(const_cast<const Calorimeter *>(this)->grid());
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
Otherwise the non-constant member function grid is recursively calls itself.
I'm having some problems with the const_cast function.
It's an operator, not a function.
I know that using const_cast is not the best practice,
It is bad practice if you design your code's architecture such that const_cast cannot be avoided. It can be an acceptable real-life workaround if const correctness has already been violated elsewhere (e.g. in libraries you have to use, although well-designed libraries do not suffer from such shortcomings).
but for this assignment I have to use it.
Says who?
Simply duplicating the code for the const CaloGrid& grid() const for the non-constant function would probably work.
Yes, and it would be best practice. Just do it.
What am I doing wrong?
You've been a bit too eager to apply the DRY (Don't Repeat Yourself) principle. This has made you write code which has accidentally caused the infinite recursion problem explained by Sam in the other answer.
And what is the point of overloading the function with a const copy of the function?
The const overload allows you to call the function on a Calorimeter const object.
It's like std::vector::operator[], just to name a prominent example. Operations like that often come in const/non-const pairs.
You can look up how your compiler implements std::vector::operator[]. There's a good chance it will just duplicate the tiny piece of code necessary and not use const_cast or other tricks.
By the way...
It may not be a good idea to have a function like grid() in the first place. It practically makes the private data member public.
If I have a vector as a private member in my class, what's the best way to access it? For example, take the following simple class
class MCL{
private:
std::vector my_vec;
public:
// Include constructor here and other member functions
}
What's the best way to access my_vec? Specifically, I would like to use a getter function to access it.
return it by const reference, or just by reference if you want to allow changing.
const std::vector<T> & getVector() const
{
return vector;
}
usage:
const std::vector<T> &v = myClass.getVector();
Create a public function called
std:vector getMyVec() {return my_vec;}
Depending on the semantics of your class, you may want to implement operator[]:
T& operator[](int i) {
return my_vec[i];
}
This way you can user [] to access the contents of your vector:
MCL a;
a[0] = 3;
std::cout << a[0] << std::endl;
Note that this may be considered abuse of operator[] or bad practice, but it is up to the developer to judge if this construct fits in the class, depending on its semantics.
Also note that this solution does not provides a way to insert or delete elements from the vector, just access to the elements already there. You may want to add other methods to do these or to implement something like:
T& operator[](int i) {
if(my_vec.size() < i)
my_vec.resize(i+1);
return my_vec[i];
}
Again, it is up to the semantics of your class and your usage pattern of it. This may or may not be a good idea.
I have several members in my class which are const and can therefore only be initialised via the initialiser list like so:
class MyItemT
{
public:
MyItemT(const MyPacketT& aMyPacket, const MyInfoT& aMyInfo)
: mMyPacket(aMyPacket),
mMyInfo(aMyInfo)
{
}
private:
const MyPacketT mMyPacket;
const MyInfoT mMyInfo;
};
My class can be used in some of our internally defined container classes (e.g. vectors), and these containers require that operator= is defined in the class.
Of course, my operator= needs to do something like this:
MyItemT&
MyItemT::operator=(const MyItemT& other)
{
mMyPacket = other.mPacket;
mMyInfo = other.mMyInfo;
return *this;
}
which of course doesn't work because mMyPacket and mMyInfo are const members.
Other than making these members non-const (which I don't want to do), any ideas about how I could fix this?
You're kind of violating the definition of const if you have an assignment operator that can change them after construction has finished. If you really need to, I think Potatoswatter's placement new method is probably best, but if you have an assignment operator your variables aren't really const, since someone could just make a new instance and use it to change their values
Rather than storing objects in your containers directly, you might be able to store pointers (or smart pointers). That way, you don't have to mutate any of the members of your class -- you get back exactly the same object as you passed in, const and all.
Of course, doing this will probably change the memory management of your application somewhat, which may well be a good enough reason not to want to.
It's a dirty hack, but you can destroy and reconstruct yourself:
MyItemT&
MyItemT::operator=(const MyItemT& other)
{
if ( this == &other ) return *this; // "suggested" by Herb Sutter ;v)
this->MyItemT::~MyItemT();
try {
new( this ) MyItemT( other );
} catch ( ... ) {
new( this ) MyItemT(); // nothrow
throw;
}
return *this;
}
Edit: lest I destroy my credibility, I don't actually do this myself, I would remove the const. However, I've been debating changing the practice, because const simply is useful and better to use wherever possible.
Sometimes there is a distinction between the resource and the value represented by an object. A member may be const through changes to value as long as the resource is the same, and it would be nice to get compile-time safety on that.
Edit 2: #Charles Bailey has provided this wonderful (and highly critical) link: http://gotw.ca/gotw/023.htm.
Semantics are tricky in any derived class operator=.
It may be inefficient because it doesn't invoke assignment operators that have been defined.
It's incompatible with wonky operator& overloads (whatever)
etc.
Edit 3: Thinking through the "which resource" vs "what value" distinction, it seems clear that operator= should always change the value and not the resource. The resource identifier may then be const. In the example, all the members are const. If the "info" is what's stored inside the "packet," then maybe the packet should be const and the info not.
So the problem isn't so much figuring out the semantics of assignment as lack of an obvious value in this example, if the "info" is actually metadata. If whatever class owns a MyItemT wants to switch it from one packet to another, it needs to either give up and use an auto_ptr<MyItemT> instead, or resort to a similar hack as above (the identity test being unnecessary but the catch remaining) implemented from outside. But operator= shouldn't change resource binding except as an extra-special feature which absolutely won't interfere with anything else.
Note that this convention plays well with Sutter's advice to implement copy construction in terms of assignment.
MyItemT::MyItemT( MyItemT const &in )
: mMyPacket( in.mMyPacket ) // initialize resource, const member
{ *this = in; } // assign value, non-const, via sole assignment method
I think you could get away with a special const proxy.
template <class T>
class Const
{
public:
// Optimal way of returning, by value for built-in and by const& for user types
typedef boost::call_traits<T>::const_reference const_reference;
typedef boost::call_traits<T>::param_type param_type;
Const(): mData() {}
Const(param_type data): mData(data) {}
Const(const Const& rhs): mData(rhs.mData) {}
operator const_reference() const { return mData; }
void reset(param_type data) { mData = data; } // explicit
private:
Const& operator=(const Const&); // deactivated
T mData;
};
Now, instead of const MyPacketT you would have Const<MyPacketT>. Not that the interface only provides one way to change it: through an explicit call to reset.
I think any use of mMyPacket.reset can easily be search for. As #MSalters said it protects against Murphy, not Machiavelli :)
You might consider making the MyPacketT and MyInfoT members be pointers to const (or smart pointers to const). This way the data itself is still marked const and immutable, but you can cleanly 'swap' to another set of const data in an assignment if that makes sense. In fact, you can use the swap idiom to perform the assignment in an exception safe manner.
So you get the benefit of const to help you prevent accidentally allowing changes that you want the design to prevent, but you still allow the object as a whole to be assigned from another object. For example, this will let you use objects of this class in STL containers.
You might look at this as a special application of the 'pimpl' idiom.
Something along the lines of:
#include <algorithm> // for std::swap
#include "boost/scoped_ptr.hpp"
using namespace boost;
class MyPacketT {};
class MyInfoT {};
class MyItemT
{
public:
MyItemT(const MyPacketT& aMyPacket, const MyInfoT& aMyInfo)
: pMyPacket(new MyPacketT( aMyPacket)),
pMyInfo(new MyInfoT( aMyInfo))
{
}
MyItemT( MyItemT const& other)
: pMyPacket(new MyPacketT( *(other.pMyPacket))),
pMyInfo(new MyInfoT( *(other.pMyInfo)))
{
}
void swap( MyItemT& other)
{
pMyPacket.swap( other.pMyPacket);
pMyInfo.swap( other.pMyInfo);
}
MyItemT const& operator=( MyItemT const& rhs)
{
MyItemT tmp( rhs);
swap( tmp);
return *this;
}
private:
scoped_ptr<MyPacketT const> pMyPacket;
scoped_ptr<MyInfoT const> pMyInfo;
};
Finally, I changed my example to use scoped_ptr<> instead of shared_ptr<> because I thought it was a more general representation of what the OP intended. However, if the 'reassignable' const members can be shared (and that's probably true, given my understanding of why the OP wants them const), then it might be an optimization to use shared_ptr<>'s and let the copy and assignment operations of the shared_ptr<> class take care of things for those objects - if you have no other members that require special copy or assign sematics, then your class just got a lot simpler, and you might even save a significant bit of memory usage by being able to share copies of the MyPacketT and MyInfoT objects.
As a common rule, it is very often considered a bad practice to use const_cast<>() in C++ code as it reveals (most of the time) a flaw in the design.
While I totally agree with this, I however wonder what are the cases were using const_cast<>() is ok and the only solution.
Could you guys please give me some examples you know/you encountered ?
Thank you very much.
it is pretty much designed to be only used with legacy APIs that are not const correct i.e. with a function you can't change that has non const interface but doesn't actually mutate anything on the interface
Like others have said, its primary purpose is to remove const from objects in order to pass to non-const correct functions you know won't modify the argument.
There is a trick (by Meyers?) to avoid code duplication, and it goes like this:
struct foo
{
const return_type& get(void) const
{
// fancy pants code that you definitely
// don't want to repeat
return theValue; // and got it
}
return_type& get(void)
{
// well-defined: Add const to *this,
// call the const version, then
// const-cast to remove const (because
// *this is non-const, this is ok)
return const_cast<return_type&>(static_cast<const foo&>(*this).get());
}
};
const_cast is also used to remove volatile modifiers, as put into practice in this (controversed) article:
http://www.drdobbs.com/184403766
I agree with your statement that its normal use is because you need to hide a 'design flaw'.
IME one of the typical usage scenarios is when you try to interface C++ to existing C code. A lot of existing C code takes C strings as char * even when the string is not modified whereas they're usually represented as something that converts to a const char * in C++. That's an impedance mismatch between the two languages that you would normally solve by using a const_cast. Of course you'd better be very sure that the code you're interfacing with doesn't get any cute ideas about modifying the data that's being passed in.
I would say that it's a code smells in newly written code, but for interfacing with older C and C++ code, it's an necessary evil. That said, I would be extremely wary of code that requires const_cast for any non-POD objects as that is normally a problem that should be solved at the design level and not the code level.
One legitimate use (in my opinion) is with std::set iterators. They are always const, in order to prevent changing the key used in the set. Changing the key would break the internal structure of the set and cause undefined behavior.
However, as long as the key doesn't change it's safe to change other data in the object.
Let's say you have an std::set like this:
std::set<MyObject> some_set;
And a class like this:
class MyObject {
public:
MyObject(const std::string &key)
: key_(key) {}
bool operator<(const MyObject &other) const {
return key_ < other.key_;
}
private:
// ...
// <some other data>
// ...
const std::string key_;
};
In the above example, the key is already const, so even if you modify the object, you cannot break the internal structure of the set.
Normally you can only get a const reference out of a set iterator:
const MyObject &object = *some_set_iterator;
But since the key is const, it's safe to const_cast the dereferenced iterator:
MyObject &object = const_cast<MyObject &>(*some_set_iterator);
One very legitimate use of this is when you have both a const and non const api (for const and non const objects respectively) as in
class Bar {
const SomeType& foo() const;
SomeType& foo();
}
Then since we don't want to duplicate the code in both functions we often use
class Bar {
SomeType& foo() {
//Actual implementation
}
const SomeType& foo() const {
return const_cast<Bar*>(this)->foo();
}
};
This is of course assuming that foo does not do something that violates the const semantics.
Yes of course, when your calling code that you can't modify and isn't const correct. It should be noted that you should only use it with calls to functions that you know for certain won't modify your data!
There is an example of const_cast usage in c++ primer(5th edition) book.
Below function returns reference to const string
// return a reference to the shorter of two strings
const string &shorterString(const string &s1, const string
&s2)
{
return s1.size() <= s2.size() ? s1 : s2;
}
The book then mentions the case when we want a non const reference.
We can call the function on a pair of nonconst string arguments, but
we’ll get a reference to a const string as the result. We might want
to have a version of shorterString that, when given nonconst
arguments, would yield a plain reference. We can write this version of
our function using a const_cast:
string &shorterString(string &s1, string &s2)
{
auto &r = shorterString(const_cast<const string&>(s1),
const_cast<const string&>(s2));
return const_cast<string&>(r);
}
This version calls the const version of shorterString by casting its
arguments to references to const. That function returns a reference to
a const string, which we know is bound to one of our original,
nonconst arguments. Therefore, we know it is safe to cast that string
back to a plain string& in the return.
According to the book, it should be used if we know it is safe to cast.