C++: is "this" pointer useless? - c++

in the code below, it does not matter whether i put "this->" or remove it. it gives same output and result in both cases.
So, what is the point of having the "this" pointer in C++? Are there other usages where it is essential?
Thanks.
#include<iostream>
using namespace std;
class square{
int l;
int w;
public:
square(int x, int y){
w = x;
l = y;
}
int getArea(){
return w * l;
};
bool AreaSmallerThan(square c){
if(this->getArea() < c.getArea())
return true;
else
return false;
}
};
int main(){
square A(2,3);
square B(1,3);
if(A.AreaSmallerThan(B))
cout<<"A is smaller than B."<<endl;
else
cout<<"A is NOT smaller than B."<<endl;
return 0;
}

TL;DR: It has it's uses. If you choose good naming practices, you generally won't need to use it often.
There are a number of cases where you would want a "pointer to the current object", for example:
struct Foo
{
void MakeCallback(eventid_t eventId)
{
scheduleCallback(eventId, callbackProxyFn, this);
}
static void callbackProxyFn(eventid_t eventId, Foo* foo)
{
// call 'callback' on the relevant object instance.
foo->callback(eventId);
}
void callback(eventid_t eventId);
};
It can also be used to resolve conflicts between names in the current object and other scopes, if you choose to use terrible naming conventions.
void Foo::bar(int n)
{
this->n = n;
}
You could avoid this (pun intended) scenario, as is common practice, by prefixing statics, globals and members:
class Player {
int m_score;
public:
Player(int score) : m_score(score) {}
};
Player g_player1;
static Player s_login; // yeah, I know, terrible, just an example tho.
A common use is in eliminating self in copy/comparison operators:
bool Foo::operator==(const Foo& rhs) const
{
if (this == &rhs)
return true;
...
}
You can also use it to produce a reference to the current object:
foo(const Foo&);
void foo(*this);

Yes there are times it is essential. A classic case is in operator=, to avoid destroying resources during self-assignment.
for example https://stackoverflow.com/a/3975092/103167
Set& Set::operator=(const Set& setEqual)
{
//first check for self assignment
if (&setEqual == this)
cout << "this is self assignment";
return *this;
}
(Note that this isn't needed when using the copy-and-swap idiom)
Accessing members via this is also frequently seen in template code which inherits from a template parameter. Those inherited names can only be found during second phase lookup, which means they need to be qualified with this->

Random example...what if you had passed an int w, int l into your getArea() function...then you need to use the this keyword to differentiate between the local parameter
int getArea(int w, int l){
return this->w * this->l;
};
Another common example might be move assignment. I have pasted an example from a Tree datastructure project I coded.
/* move assignment */
TreeSet& operator= (TreeSet&& rhs)
{
clearAll(rootPtr);
this->rootPtr = rhs.rootPtr;
rhs.rootPtr = nullptr;
return *this;
}
And finally another example for an iterator I wrote...when overloading the ++ operator on an iterator, you want to return the resulting iterator..
/* Update the current pointer to advance to the node
* with the next larger value
*/
const_iterator& operator++ () {
//I have deleted all the logic for the sake of not taking up a ton of space..
return *this;
}

Generally speaking, the 'this' pointer can be useful when an instance of a class is invoking some method and the instance itself needs to be passed from within the method to some function outside of the class.

Related

Member functions that are sometimes const

I have a class design similar to the following:
class MyClass {
public:
bool IsValid() const;
void MakeValid();
private:
bool CheckValidity(bool fix);
};
bool MyClass::IsValid() const {
// Check validity, but don't fix any problems found. Doesn't work.
return CheckValidity(false);
}
void MyClass::MakeValid() {
// Check validity and fix problems found.
CheckValidity(true);
}
IsValid should be const, because it doesn't make changes. MakeValid should be non-const, because it does make changes. They share the same implementation, CheckValidity, but because CheckValidity may or may not make changes, it can't be marked const.
What's the best way to handle this? The simplest approach is to just use const_cast, but casting away const feels a bit dirty:
bool MyClass::IsValid() const {
// Check validity, but don't fix any problems found.
return const_cast<MyClass*>(this)->CheckValidity(false);
}
Is this a legitimate use of const_cast? Is there a better approach?
I'm assuming your implementation looks similar to this:
bool CheckValidity(bool fix)
{
// Actually check validity.
bool isValid = ...;
if (!isValid && fix)
{
// Attempt to fix validity (and update isValid).
isValid = ...;
}
return isValid;
}
You really have two different functions shoved into one. One of the key indicators of this kind of entanglement is the boolean argument to the function... which smells because the caller cannot immediately discern whether to put true or false without referencing code/docs.
Split up the method:
bool CheckValidity() const
{
// Actually check validity.
bool isValid = ...;
return isValid;
}
void FixValidity()
{
// Attempt to fix validity.
// ...
}
And then your public methods can make the calls more appropriately.
bool IsValid() const
{
// No problem: const method calling const method
return CheckValidity();
}
void MakeValid()
{
if (!CheckValidity()) // No problem: non-const calling const
{
FixValidity(); // No problem: non-const calling non-const
}
}
Here is an approach that might be useful in some cases. It might be overkill for your particular situation.
Your CheckValidity function could be passed a handler object. The CheckValidity function would find what was not valid, and call an appropriate method of the handler object. You could have many different methods for different kinds of validity violations, and those methods could be passed enough information that the problem could be fixed if necessary. To implement IsValid, you just need to pass a handler which sets a flag indicating there was a problem. To implement MakeValid, you can pass a handler which actually fixes the problem. The const issue is addressed by having the fixing handler keep a non-const reference to the object.
Here is an example:
class MyClass {
public:
bool IsValid() const
{
bool flag = false;
CheckValidity(FlagProblems{flag});
return flag;
}
void MakeValid()
{
CheckValidity(FixProblems{*this});
}
private:
struct FlagProblems {
bool& flag;
void handleType1(arg1,arg2) const { flag = true; }
void handleType2(arg1,arg2,arg3) const { flag = true; }
.
.
.
};
struct FixProblems {
MyClass& object;
void handleType1(arg1,arg2) const { ... }
void handleType2(arg1,arg2,arg3) const { ... }
.
.
.
};
template <typename Handler>
bool CheckValidity(const Handler &handler) const
{
// for each possible problem:
// if it is a type-1 problem:
// handler.handleType1(arg1,arg2);
// if it is a type-2 problem:
// handler.handleType2(arg1,arg2,arg3);
// .
// .
// .
}
};
Using the template allows for maximum efficiency. Alternatively, using a base class with virtual functions for the handler might provide a smaller executable size.
If the ways in which the object can be invalid are simpler, then having CheckValidity return a struct containing the relevant information may be more straightforward.
You can use a template specialization to separate the parts that only have purpose on a non-const object.
Following is an implementation for a toy class. It has a single c-array member v with 10 ints, and, for our purposes, it is only valid when every single one of them equals to zero.
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
};
See that I already made a function member that fixes an invalid position, and a nice constructor that initializes it as an invalid object(don't do that :D)
Since we are going to use templates, we need to move the implementation of the check/fix cycle outside of the class. In order for the relevant functions to be able to access v and the fix() method, we'll make them friends. Our code now looks like:
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
template<typename T>
friend void fix(T& obj, int pos);
template<typename T>
friend bool check(T& obj);
};
check()'s implementation is straightforward:
// Check and maybe fix object
template<typename T>
bool check(T& obj){
bool result = true;
for(int i=0;i<10;i++) {
if (obj.v[i]) {
result = false;
fix(obj, i);
}
}
return result;
}
Now here is the tricky part. We want our fix() function to change behaviour based on constness. For that we'll need to specialize the template. For a non-const object, it will fix the position. For a const one, it will do nothing:
// For a regular object, fix the position
template<typename T>
void fix(T& obj, int pos) { obj.fix(pos);}
// For a const object, do nothing
template<typename T>
void fix(const T& obj, int pos) {}
Finally, we write our is_valid() and make_valid() methods, and here we have the full implementation:
#include <iostream>
class ten_zeroes {
int v[10];
void fix(int pos) {v[pos] = 0;}
public:
ten_zeroes() { // construct as invalid object
for (int i=0;i<10;i++) {
v[i] = i;
}
}
bool is_valid() const {return check(*this);} // since this is const, it will run check with a const ten_zeroes object
void make_valid() { check(*this);} // since this is non-const , it run check with a non-const ten_zeroes object
template<typename T>
friend void fix(T& obj, int pos);
template<typename T>
friend bool check(T& obj);
};
// For a regular object, fix the position
template<typename T>
void fix(T& obj, int pos) { obj.fix(pos);}
// For a const object, do nothing
template<typename T>
void fix(const T& obj, int pos) {}
// Check and maybe fix object
template<typename T>
bool check(T& obj){
bool result = true;
for(int i=0;i<10;i++) {
if (obj.v[i]) {
result = false;
fix(obj, i);
}
}
return result;
}
int main(){
ten_zeroes a;
std::cout << a.is_valid() << a.is_valid(); // twice to make sure the first one didn't make any changes
a.make_valid(); // fix the object
std::cout << a.is_valid() << std::endl; // check again
}
I hope you don't mind the main() function there. It will test our little toy, and output 001, as expected. Now any maintenance on this code will not have to deal with code duplication, what you probably was intending to avoid. I hope this was helpful.
Of course, if you intend to hide these implementation details from the final user, you should move them to an appropriate detail namespace. I'll leave that up to you :)

Over-using mutable to enhance security?

Suppose I have a class that has an array of pointers, and I have a method that dereferences a pointer and returns it as a reference. I want to allow the method caller to call non-const methods of the object the pointer is pointing to, but also want to protect myself from the caller changing what the pointer is pointing to. If I return a const reference, I have to mark many of the pointer object's methods as const, and hence many of its class member variables as mutable.
Is this bad practice? If so, how do I get around this?
Is there performance penalty for over-using mutable?
Example:
#include <iostream>
#include <array>
#include <memory>
class Counter
{
public:
Counter();
void hit() const;
void reset();
unsigned count() const;
private:
mutable unsigned count_;
};
Counter::Counter() : count_(0) {}
void Counter::hit() const { ++count_; }
void Counter::reset() { count_ = 0; }
unsigned Counter::count() const { return count_; }
class CircularArray
{
public:
CircularArray();
const Counter& next() const;
private:
mutable unsigned i_;
std::array<std::unique_ptr<Counter>, 3> arr_;
};
CircularArray::CircularArray() : i_(2)
{
arr_[0] = std::unique_ptr<Counter>(new Counter);
arr_[1] = std::unique_ptr<Counter>(new Counter);
arr_[2] = std::unique_ptr<Counter>(new Counter);
}
const Counter& CircularArray::next() const { return *arr_[(i_ = (i_ + 1) % 3)]; }
int main()
{
CircularArray circular;
const Counter* p;
p = &circular.next();
p->hit();
p->hit();
Counter c;
//*p = c; // <-- Want to prevent this
}
To extend what I was saying, there is no point in abusing mutable for this. If this is all you want to prevent:
*p = /* ... */;
then it can be done much more easily by deleting the assignment operator of Counter:
class Counter
{
void operator=(const Counter&) = delete;
// ...
};
Remember that the assignment operator does not affect the identity of the object: it doesn't change its address. Semantically, an assignment involving of modifying this object to replicate the state of another object. In fact, even if you forbid me from using the assignment operator somehow, I could still do this:
// a very inefficient way of performing `*p = c`
p->reset();
while (p->count() != c.count())
p->hit();
This achieves the exact same result as performing an assignment, albeit very clumsily and inefficiently.
Performing an assignment is no different than calling a non-const member function that accepts a single argument of type const Counter&. Hypothetically, you could redefine the assignment operator to do absolutely nothing at all if you wanted to (it would be a bad idea though).

What is purpose of a "this" pointer in C++? [duplicate]

This question already has answers here:
When should I make explicit use of the `this` pointer?
(12 answers)
Closed 6 years ago.
What is purpose of this keyword. Doesn't the methods in a class have access to other peer members in the same class ? What is the need to call a this to call peer methods inside a class?
Two main uses:
To pass *this or this as a parameter to other, non-class methods.
void do_something_to_a_foo(Foo *foo_instance);
void Foo::DoSomething()
{
do_something_to_a_foo(this);
}
To allow you to remove ambiguities between member variables and function parameters. This is common in constructors.
MessageBox::MessageBox(const string& message)
{
this->message = message;
}
(Although an initialization list is usually preferable to assignment in this particular example.)
Helps in disambiguating variables.
Pass yourself as a parameter or return yourself as a result
Example:
struct A
{
void test(int x)
{
this->x = x; // Disambiguate. Show shadowed variable.
}
A& operator=(A const& copy)
{
x = copy.x;
return *this; // return a reference to self
}
bool operator==(A const& rhs) const
{
return isEqual(*this, rhs); // Pass yourself as parameter.
// Bad example but you can see what I mean.
}
private:
int x;
};
Consider the case when a parameter has the same name as a class member:
void setData(int data){
this->data = data;
}
Resolve ambgiguity between member variables/functions and those defined at other scopes
Make explicit to a reader of the code that a member function is being called or a member variable is being referenced.
Trigger IntelliSense in the IDE (though that may just be me).
The expression *this is commonly used to return the current object from a member function:
return *this;
The this pointer is also used to guard against self-reference:
if (&Object != this) {
// do not execute in cases of self-reference
It lets you pass the current object to another function:
class Foo;
void FooHandler(Foo *foo);
class Foo
{
HandleThis()
{
FooHandler(this);
}
};
Some points to be kept in mind
This pointer stores the address of
the class instance, to enable pointer
access of the members to the member
functions of the class.
This pointer is not counted for
calculating the size of the object.
This pointers are not accessible for
static member functions.
This pointers are not modifiable
Look at the following example to understand how to use the 'this' pointer explained in this C++ Tutorial.
class this_pointer_example // class for explaining C++ tutorial
{
int data1;
public:
//Function using this pointer for C++ Tutorial
int getdata()
{
return this->data1;
}
//Function without using this pointer
void setdata(int newval)
{
data1 = newval;
}
};
Thus, a member function can gain the access of data member by either using this pointer or not.
Also read this to understand some other basic things about this pointer
It allows you to get around members being shadowed by method arguments or local variables.
The this pointer inside a class is a reference to itself. It's needed for example in this case:
class YourClass
{
private:
int number;
public:
YourClass(int number)
{
this->number = number;
}
}
(while this would have been better done with an initialization list, this serves for demonstration)
In this case you have 2 variables with the same name
The class private "number"
And constructor parameter "number"
Using this->number, you let the compiler know you're assigning to the class-private variable.
For example if you write an operator=() you must check for self assignment.
class C {
public:
const C& operator=(const C& rhs)
{
if(this==&rhs) // <-- check for self assignment before anything
return *this;
// algorithm of assignment here
return *this; // <- return a reference to yourself
}
};
The this pointer is a way to access the current instance of particular object. It can be used for several purposes:
as instance identity representation (for example in comparison to other instances)
for data members vs. local variables disambiguation
to pass the current instance to external objects
to cast the current instance to different type
One more purpose is to chaining object:
Consider the following class:
class Calc{
private:
int m_value;
public:
Calc() { m_value = 0; }
void add(int value) { m_value += value; }
void sub(int value) { m_value -= value; }
void mult(int value) { m_value *= value; }
int getValue() { return m_value; }
};
If you wanted to add 5, subtract 3, and multiply by 4, you’d have to do this:
#include
int main()
{
Calc calc;
calc.add(5); // returns void
calc.sub(3); // returns void
calc.mult(4); // returns void
std::cout << calc.getValue() << '\n';
return 0;
}
However, if we make each function return *this, we can chain the calls together. Here is the new version of Calc with “chainable” functions:
class Calc
{
private:
int m_value;
public:
Calc() { m_value = 0; }
Calc& add(int value) { m_value += value; return *this; }
Calc& sub(int value) { m_value -= value; return *this; }
Calc& mult(int value) { m_value *= value; return *this; }
int getValue() { return m_value; }
};
Note that add(), sub() and mult() are now returning *this. Consequently, this allows us to do the following:
#include <iostream>
int main()
{
Calc calc;
calc.add(5).sub(3).mult(4);
std::cout << calc.getValue() << '\n';
return 0;
}
We have effectively condensed three lines into one expression.
Copied from :http://www.learncpp.com/cpp-tutorial/8-8-the-hidden-this-pointer/
Sometimes you want to directly have a reference to the current object, in order to pass it along to other methods or to store it for later use.
In addition, method calls always take place against an object. When you call a method within another method in the current object, is is equivalent to writing this->methodName()
You can also use this to access a member rather than a variable or argument name that "hides" it, but it is (IMHO) bad practice to hide a name. For instance:
void C::setX(int x)
{
this->x = x;
}
For clarity, or to resolve ambiguity when a local variable or parameter has the same name as a member variable.
It also allows you to test for self assignment in assignment operator overloads:
Object & operator=(const Object & rhs) {
if (&rhs != this) {
// do assignment
}
return *this;
}
It also allows objects to delete themselves. This is used in smart pointers implementation, COM programming and (I think) XPCOM.
The code looks like this (excerpt from some larger code):
class counted_ptr
{
private:
counted_ptr(const counted_ptr&);
void operator =(const counted_ptr&);
raw_ptr_type _ptr;
volatile unsigned int _refcount;
delete_function _deleter;
public:
counted_ptr(raw_ptr_type const ptr, delete_function deleter)
: _ptr(ptr), _refcount(1), _deleter(deleter) {}
~counted_ptr() { (*_deleter)(_ptr); }
unsigned int addref() { return ++_refcount; }
unsigned int release()
{
unsigned int retval = --_refcount;
if(0 == retval)
>>>>>>>> delete this;
return retval;
}
raw_ptr_type get() { return _ptr; }
};
The double colon in c++ is technically known as "Unary Scope resolution operator".
Basically it is used when we have the same variable repeated for example inside our "main" function (where our variable will be called local variable) and outside main (where the variable is called a global variable).
C++ will alwaysexecute the inner variable ( that is the local one).
So imagine you want to use the global variable "Conundrum" instead the local one just because the global one is expressed as a float instead of as an integer:
#include <iostream>
using namespace std;
float Conundrum=.75;
int main()
{
int Conundrum =75;
cout<<::Conundrum;
}
So in this case the program will use our float Conundrum instead of the int Conundrum.

avoiding the tedium of optional parameters

If I have a constructor with say 2 required parameters and 4 optional parameters, how can I avoid writing 16 constructors or even the 10 or so constructors I'd have to write if I used default parameters (which I don't like because it's poor self-documentation)? Are there any idioms or methods using templates I can use to make it less tedious? (And easier to maintain?)
You might be interested in the Named Parameter Idiom.
To summarize, create a class that holds the values you want to pass to your constructor(s). Add a method to set each of those values, and have each method do a return *this; at the end. Have a constructor in your class that takes a const reference to this new class. This can be used like so:
class Person;
class PersonOptions
{
friend class Person;
string name_;
int age_;
char gender_;
public:
PersonOptions() :
age_(0),
gender_('U')
{}
PersonOptions& name(const string& n) { name_ = n; return *this; }
PersonOptions& age(int a) { age_ = a; return *this; }
PersonOptions& gender(char g) { gender_ = g; return *this; }
};
class Person
{
string name_;
int age_;
char gender_;
public:
Person(const PersonOptions& opts) :
name_(opts.name_),
age_(opts.age_),
gender_(opts.gender_)
{}
};
Person p = PersonOptions().name("George").age(57).gender('M');
What if you made a parameter object that contained all the fields? Then you could just pass that, and just set whichever fields you need. There's probably a name for that pattern, not sure what it is though...
UPDATE:
Code might look like somewhat this:
paramObj.x=1;
paramObj.y=2;
paramObj.z=3;
paramObj.magic=true;
... //set many other "parameters here"
someObject myObject = new someObject(paramObj);
and inside the someObject constructor you can set defaults for things that were not already set (or raise an error if it was mandatory).
Honestly, I'm not a big fan of this solution, but I've used it once or twice when paramObj made sense by containing a set of data that usually all went together (so we could use it for more than just constructors), and it was better than multiple constructors. I found that it was ugly but it worked, YMMV.
And now for the "Boost has something for it" answer:
The Boost Parameter Library seems to be a good fit to your use case.
All new for C++17
#include <optional>
using optional_int = std::optional<int>;
class foo {
int arg0, arg1; // required
int arg2, arg3; // optional
const int default_2 = -2;
const int default_3 = -3;
public:
foo(int arg0, int arg1, optional_int opt0 = {}, optional_int opt1 = {})
: arg0(arg0), arg1(arg1)
, arg2(opt0.value_or(default_2))
, arg3(opt1.value_or(default_3))
{ }
};
int main() {
foo bar(42, 43, {}, 45); // Take default for opt0 (arg2)
return 0;
}
I have a cubic spline implementation that allows the user optionally to specify the first derivative at either the left end, the right end, or both. If a derivative is not specified, then the code in effect calculates one, by assuming that the second derivative is zero (the so-called "natural spline"). Here is a fragment for the left end.
// Calculate the second derivative at the left end point
if (!left_deriv.has_value()) {
ddy[0]=u[0]=0.0; // "Natural spline"
} else {
const real yP0 = left_deriv.value();
ddy[0] = -0.5;
u[0]=(3.0/(x[1]-x[0]))*((y[1]-y[0])/(x[1]-x[0])-yP0);
}

const and pointers

Edit1: I realize this is hard to understand this question without having an insight of what I'm trying to do. The class A is not complete but it essentially stand for a C-array "proxy" (or "viewer" or "sampler"). One interesting usage is too present a C-array as a 2d grid (the relevant function are not shown here). The property of this class are the following:
it should not own the data - no deep copyy
it should be copyable/assignable
it should be lightweight (
it should preserve constness (I'm having trouble with this one)
Please do not question the purpose or the design: they are the hypothesis of the question.
First some code:
class A
{
private:
float* m_pt;
public:
A(float* pt)
:m_pt(pt)
{}
const float* get() const
{
return m_pt;
}
void set(float pt)
{
*m_pt = pt;
}
};
void gfi()
{
float value = 1.0f;
const A ac(&value);
std::cout<<(*ac.get())<<std::endl;
A a = ac;
a.set(2.0f);
std::cout<<(*ac.get())<<std::endl;
}
Calling "gfi" generate the following output:
1
2
Assigning a with ac is a cheap way to shortcut the constness of ac.
Is there a better way to protect the value which m_pt point at?
Note that I DO want my class to be copyable/assignable, I just don't want it to loose its constness in the process.
Edit0: I also DO want to have a pointer in there, and no deep copy please (let say the pointer can be a gigantic array).
Edit2: thanks to the answers, I came to the conclusion that a "const constructor" would be a useful thing to have (at least in this context). I looked it up and of course I'm not the same one who reached this conclusion. Here's an interesting discussion:
http://www.rhinocerus.net/forum/language-c-moderated/569757-const-constructor.html
Edit3: Finally got something which I'm happy with. Thanks for your help. Further feedback is more than welcome
template<typename T>
class proxy
{
public:
typedef T elem_t;
typedef typename boost::remove_const<T>::type elem_unconst_t;
typedef typename boost::add_const<T>::type elem_const_t;
public:
elem_t* m_data;
public:
proxy(elem_t* data = 0)
:m_data(data)
{}
operator proxy<elem_const_t>()
{
return proxy<elem_const_t>(m_data);
}
}; // end of class proxy
void test()
{
int i = 3;
proxy<int> a(&i);
proxy<int> b(&i);
proxy<const int> ac(&i);
proxy<const int> bc(&i);
proxy<const int> cc = a;
a=b;
ac=bc;
ac=a;
//a=ac; // error C2679: binary '=' : no operator found which takes a right-hand operand of type...
//ac.m_data[0]=2; // error C3892: 'ac' : you cannot assign to a variable that is const
a.m_data[0]=2;
}
Your class is badly designed:
it should use float values, not pointers
if you want to use pointers, you probably need to allocate them dynamically
and then you need to give your class a copy constructor and assignment operator (and a destructor) , which will solve the problem
Alternatively, you should prevent copying and assignment by making the copy constructor and assignment op private and then not implementing them.
You can trick around with proxy pattern and additional run-time constness boolean member. But first, please tell us why.
Effectively your class is like an iterator that can only see one value. It does not encapsulate your data just points to it.
The problem you are facing has been solved for iterators you should read some documentation on creating your own iterator and const_iterator pairs to see how to do this.
Note: in general a const iterator is an iterator that cannot be incremented/decremented but can change the value it points to. Where as a const_iterator is a different class that can be incremented/decremented but the value it points to cannot be changed.
This is the same as the difference between const float * and float *const. In your case A is the same as float * and const A is the same as float *const.
To me your choices seem to be:
Encapsulate your data.
Create a separate const_A class like iterators do
Create your own copy constructor that does not allow copies of const A eg with a signature of A(A & a);
EDIT: considering this question some more, I think you are misinterpreting the effect of const-correctness on member pointers. Consider the following surprising example:
//--------------------------------------------------------------------------------
class CNotSoConstPointer
{
float *mp_value;
public:
CNotSoConstPointer(float *ip_value) : mp_value(ip_value) {}
void ModifyWithConst(float i_value) const
{
mp_value[0] = i_value;
}
float GetValue() const
{
return mp_value[0];
}
};
//--------------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])
{
float value = 12;
const CNotSoConstPointer b(&value);
std::cout << b.GetValue() << std::endl;
b.ModifyWithConst(15);
std::cout << b.GetValue() << std::endl;
while(!_kbhit()) {}
return 0;
}
This will output 12 and then 15, without ever being "clever" about the const-correctness of the const not-so-const object. The reason is that only the pointer ITSELF is const, not the memory it points to.
If the latter is what you want, you'll need a lot more wrapping to get the behavior you want, like in my original suggestion below or Iain suggestion.
ORIGINAL ANSWER:
You could create a template for your array-proxy, specialized on const-arrays for the const version. The specialized version would have a const *m_pt, return a const pointer, throw an error when you try to set, and so on.
Edit: Something like this:
template<typename T>
class TProxy
{
T m_value;
public:
TProxy(T i_t) : m_value(i_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.m_value) {}
T get() { return m_value; }
void set(T i_t) { m_value = i_t; }
};
template<typename T>
class TProxy<const T *>
{
const T *mp_value;
public:
TProxy(const T *ip_t) : mp_value(ip_t) {};
template<typename T>
TProxy(const TProxy<T> &i_rhs) : m_value(i_rhs.mp_value) {}
T get() { return m_value; }
};
Why not replace float* with float in A. If you don't either the original owner of the float that the float* references can change it, or anyone prepared to do a mutable cast on the return value from a::get.
const is always just a hint to the compiler; there are no ways to make a variable permanently read-only.
I think you should use deep copy and define your own assingment operator and copy constructor.
Also to return handle to internal data structure in not a good practice.
You can deny the copy-constructor for certain combinations of arguments:
For instance, adding the constructor;
A(A& a) :m_pt(a.m_pt) { m_pt = a.m_pt; }
prevents any instance of A being initialised with a const A.
This also prevents const A a2 = a1 where a1 is const, but you should never need to do this anyway, since you can just use a1 directly - it's const even if you could make a copy, a2 would be forever identical to a1.