const-correctness for this and member functions - c++

assuming that I have a generic class A
class A {
...
int a; // a member
void foo() const{...} // a member function qualified as const
...
};
this implies that if I declare an instance of A like A k; and then I call k.foo(); the this pointer that is acting on/inside that call to foo is something of type const A * const .
Now I would like to know why the code in this blog post works, especially about why this doesn't apply to global variables.
My explanation is about an hidden operation about pointer aliasing, like the this pointer being copied implicitly and during this copy the result is not const anymore ( for some reason ... ) but it's still a this pointer meaning that is a pointer to the same instance.
My question is about: what really const does if it's applied after the declaration of an interface for a member function ? Do you have a specific answer for the linked blog post ?
code from the blog
#include <iostream>
class counter {
public:
int i;
counter();
int inspect() const;
void increment();
};
counter sigma_inspect; // sigma_inspect is global
counter::counter() { i = 0; }
int counter::inspect() const {
sigma_inspect.increment();
return i;
}
void counter::increment() {
++i;
return;
}
int main(void) {
counter a;
std::cout << a.inspect() << "\n";
std::cout << sigma_inspect.inspect() << "\n";
std::cout << sigma_inspect.inspect() << "\n";
return 0;
}

The call in the blog post is using sigma_inspect which is non-const and it is calling a non-const method on it instead of calling said method through the const this pointer. So what? The author seems to expect magic instead of the obvious of what he wrote. It's like having
T* t = ...;
const T* ct = t;
t->foo(); // foo() is not const, but hey,
// I also have a const pointer now (ct),
// so why can I still use this???
Generally, if someone calls C++ stupid it tells you more about the author instead of the language :)

Related

Is it safe to pass lambda to function that is going out of scope (lambda executes after the method returns)?

I am learning C++ so maybe my question is dumb. I am creating a function that takes a lambda as a parameter. I just want to know if its safe to call it when the lambda function goes out of scope. With code is easier to explain what I mean:
struct SomeStruct
{
// store pointer to callback function
void (*callback)(bool);
int arg1;
int arg2;
};
void some_method(int arg1, int arg2, void (*on_complete_callback)(bool))
{
SomeStruct s;
s.callback = on_complete_callback;
s.arg1 = arg1;
s.arg2 = arg2;
// this helper class will copy the struct even though it is passed by reference
SomeHelperClass->SomeQueue.enqueue( &s );
// do work on a separate task/thread
SomeHelperClass->CreateThread([](){
// get copy of struct
SomeStruct s_copy;
SomeHelperClass->SomeQueue.dequeue( &s_copy );
// do work that takes time to complete
// IS IT SAFE TO CALL THIS CALLBACK FUNCTION?
s_copy.callback(true);
});
}
So my question is given that code if its safe to have something like this?
void method_1()
{
void (*foo)(bool) = [](bool completedCorrectly)
{
cout << "task completed :" << completedCorrectly << endl;
};
some_method(1,2,foo);
// at this point foo should be deleted no?
// why does this work if foo is executed after method_1 completes and its stack is deleted?
// can I have code like that?
}
Edit 2
Here is the same question with working code instead of pseudo code:
#include <iostream> //for using cout
using namespace std; //for using cout
// 3 pointers
int* _X; // points to integer
int* _Y; // points to integer
void (*_F)(int); // points to function
void print_values()
{
cout << "x=" << *_X << " and y=" << *_Y << endl;
}
void some_function()
{
// create variables that live on stack of some_function
int x = 1;
int y = 2;
void (*foo)(int) = [](int someInt)
{
cout << "value passed to lambda is:" << someInt << endl;
};
// point global variables to variables created on this stack x,y and foo
_X = &x;
_Y = &y;
_F = foo;
// works
_F(11);
// works
print_values();
// when exiting variables x,y and foo should be deleted
}
int main(void)
{
// call some function
some_function();
// DOES NOT WORK (makes sense)
print_values();
// WHY DOES THIS WORK? WHY FOO IS NOT DISTROYED LIKE X AND Y?
_F(10);
return 0;
}
If I where to call that method many times and each time with a different lambda will it work? Will the callback method call the correct lambda every time?
A lambda expression is like a class. It is a blueprint for instantiating objects. Classes exist only in source code. A program actually works with objects created from the blueprint defined by a class. Lambda expressions are a source code blueprint for creating closures. Each lambda expression is transformed into a class by the compiler and instantiated into an object called closure. This class has the ability to capture values (that's that the [] part does) and take parameters (that's that the () part does) for its call operator.
Here is an example:
int main()
{
int i = 42;
auto l = [i](int const x){std::cout << x+i << '\n';};
l(2);
}
The compiler transforms this into something similar to the following (generated with https://cppinsights.io/).
int main()
{
int i = 42;
class __lambda_6_11
{
public:
inline /*constexpr */ void operator()(const int x) const
{
std::operator<<(std::cout.operator<<(x + i), '\n');
}
private:
int i;
public:
__lambda_6_11(int & _i)
: i{_i}
{}
};
__lambda_6_11 l = __lambda_6_11{i};
l.operator()(2);
}
You can see here a class that implements the call operator (operator()) with an int argument. You can also see the constructor taking an argument of type int. And then you can see the instantiation of this class at the end of main and the invocation of its call operator.
I hope this helps you understand better how lambdas work.

Is it safe to cast between a function pointer and a member function pointer? [duplicate]

I've inherited some C++ code and I've been tasked with getting rid of warnings.
Here we have a member function pointer being cast to a function pointer.
I understand that member function pointers are "different" from function pointers, in that there is an implicit 'this' parameter involved under the hood. However my predecessor appears to have made explicit use of this fact, by casting from a member function pointer to a function pointer with an additional first parameter inserted.
My Questions are:
A) Can I get rid of the compiler warning?
B) To what extent is this code guaranteed to work?
I've cut it down to a small main.cpp for the purposes of this question:
#define GENERIC_FUNC_TYPE void(*)(void)
#define FUNC_TYPE int(*)(void *)
class MyClass
{
public:
MyClass(int a) : memberA(a) {}
int myMemberFunc()
{
return memberA;
}
private:
int memberA;
};
int main(int argc, char*argv[])
{
int (MyClass::* memberFunc) () = &MyClass::myMemberFunc;
MyClass myObject(1);
std::cout << (myObject.*memberFunc)() << std::endl;
// All good so far
// Now get naughty, store it away in a very basic fn ptr
void(*myStoredFunction)(void) = (GENERIC_FUNC_TYPE)memberFunc; // Compiler warning
// Reinterpret the fn pointer as a pointer to fn, with an extra object parameter
int (*myExtractedFunction)(void*) = (FUNC_TYPE)myStoredFunction;
// Call it
std::cout << myExtractedFunction(&myObject) << std::endl;
}
The code compiles with one warning under g++, and as intended outputs two 1's:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:27:53: warning: converting from ‘int (MyClass::*)()’ to ‘void (*)()’ [-Wpmf-conversions]
void(*myStoredFunction)(void) = (GENERIC_FUNC_TYPE)memberFunc; // Compiler warning
^
IMHO this code is making assumptions about the underlying mechanisms of the compiler. Or maybe these assumptions are valid for all C++ compilers - Can anyone help?
(In the actual code we're storing a whole bunch of function pointers by name in a map. These functions all have different signatures, which is why they are all cast to the same signature void(*)(void). This is analogous to the myStoredFunction above. They are then cast to the individual signatures at the point of calling, analogous to myExtractedFunction above.)
How about create functions which avoid the cast entirely:
template <typename C, void (C::*M)()>
void AsFunc(void* p)
{
(static_cast<C*>(p)->*M)();
}
then
void (*myExtractedFunction)(void*) = &AsFunc<MyClass, &MyClass::myMemberFunc>;
In C++17, with some traits, you might even have template <auto *M> void AsFunc(void* p) and void(*myStoredFunction)(void*) = &AsFunc<&MyClass::myMemberFunc>;
To answer the question in the title, no, you can't legally cast a pointer-to-member-function to a pointer-to-function. Presumably, that's what the "Compiler warning" on the line with that cast said.
A conforming compiler is required to issue a diagnostic when confronted with ill-formed code (that's a bit oversimplified), and this one did. It gave a warning. Having done that, the compiler is free to do something implementation-specific, which it seems to have done: it compiled the code into something that does what you were hoping for.
Compilers are free to represent pointers to member functions in any way that works, and for non-virtual functions, that could be just a "normal" pointer to function. But try that with a virtual function; I'll bet the consequences are more harsh.
A) Can I get rid of the compiler warning?
Yes - wrap the member function in a call from a static function
(This is a low-tech variant of #Jarod42's template based answer)
B) To what extent is this code guaranteed to work?
It's not (summarizing #Pete Becker's answer). Until you get rid of the warning.
Here's the jist of what we went with. We kept it simple to minimize disruption to the code. We avoided advanced C++ features to maximize the number of people who can work on the code.
#include <iostream>
class MyClass
{
public:
MyClass(int a) : memberA(a) {}
static int myMemberFuncStatic(MyClass *obj)
{
return obj->myMemberFunc();
}
int myMemberFunc()
{
return memberA;
}
private:
int memberA;
};
typedef void(*GENERIC_FUNC_TYPE)(void);
typedef int(*FUNC_TYPE)(MyClass *);
int main(int argc, char*argv[])
{
int (* staticFunc) (MyClass *) = &MyClass::myMemberFuncStatic;
MyClass myObject(1);
std::cout << staticFunc(&myObject) << std::endl;
// All good so far
// This is actually legal, for non-member functions (like static functions)
GENERIC_FUNC_TYPE myStoredFunction = reinterpret_cast<GENERIC_FUNC_TYPE> (staticFunc); // No compiler warning
// Reinterpret the fn pointer as the static function
int (*myExtractedFunction)(MyClass*) = (FUNC_TYPE)myStoredFunction;
// Call it
std::cout << myExtractedFunction(&myObject) << std::endl;
}
Since you apparently need to call a function by name on some "untyped" object (void*) while passing in a number of arguments that differ by function, you need some kind of multiple-dispatch. A possible solution is:
#include <string>
#include <iostream>
#include <stdexcept>
#include <functional>
#include <utility>
#include <map>
template <typename Subj>
using FunctionMap = std::map<std::string, std::function<void (Subj&, const std::string&)>>;
class AbstractBaseSubject {
public:
virtual void invoke (const std::string& fName, const std::string& arg) = 0;
};
template <typename Class>
class BaseSubject : public AbstractBaseSubject {
public:
virtual void invoke (const std::string& fName, const std::string& arg) {
const FunctionMap<Class>& m = Class::functionMap;
auto iter = m.find (fName);
if (iter == m.end ())
throw std::invalid_argument ("Unknown function \"" + fName + "\"");
iter->second (*static_cast<Class*> (this), arg);
}
};
class Cat : public BaseSubject<Cat> {
public:
Cat (const std::string& name) : name(name) {}
void meow (const std::string& arg) {
std::cout << "Cat(" << name << "): meow (" << arg << ")\n";
}
static const FunctionMap<Cat> functionMap;
private:
std::string name;
};
const FunctionMap<Cat> Cat::functionMap = {
{ "meow", [] (Cat& cat, const std::string& arg) { cat.meow (arg); } }
};
class Dog : public BaseSubject<Dog> {
public:
Dog (int age) : age(age) {}
void bark (float arg) {
std::cout << "Dog(" << age << "): bark (" << arg << ")\n";
}
static const FunctionMap<Dog> functionMap;
private:
int age;
};
const FunctionMap<Dog> Dog::functionMap = {
{ "bark", [] (Dog& dog, const std::string& arg) { dog.bark (std::stof (arg)); }}
};
int main () {
Cat cat ("Mr. Snuggles");
Dog dog (7);
AbstractBaseSubject& abstractDog = dog; // Just to demonstrate that the calls work from the base class.
AbstractBaseSubject& abstractCat = cat;
abstractCat.invoke ("meow", "Please feed me");
abstractDog.invoke ("bark", "3.14");
try {
abstractCat.invoke ("bark", "3.14");
} catch (const std::invalid_argument& ex) {
std::cerr << ex.what () << std::endl;
}
try {
abstractCat.invoke ("quack", "3.14");
} catch (const std::invalid_argument& ex) {
std::cerr << ex.what () << std::endl;
}
try {
abstractDog.invoke ("bark", "This is not a number");
} catch (const std::invalid_argument& ex) {
std::cerr << ex.what () << std::endl;
}
}
Here, all classes with functions to be called this way need to derive from BaseSubject (which is a CRTP). These classes (here: Cat and Dog, let's call them "subjects") have different functions with different arguments (bark and meow - of course more than one function per subject is possible). Each subject has its own map of string-to-function. These functions are not function pointers, but std::function<void (SubjectType&,const std::string&)> instances. Each of those should call the respective member function of the object, passing in the needed arguments. The arguments need to come from some kind of generic data representation - here, I chose a simple std::string. It might be a JSON or XML object depending on where your data comes from. The std::function instances need to deserialize the data and pass it as arguments. The map is created as a static variable in each subject class, where the std::function instances are populated with lambdas. The BaseSubject class looks up the function instance and calls it. Since the subject class should always directly derive from BaseSubject<Subject>, pointers of type BaseSubject<Subject>* may be directly and safely cast to Subject*.
Note that there is no unsafe cast at all - it is all handled by virtual functions. Therefore, this should be perfectly portable. Having one map per subject class is typing-intensive, but allows you to have identically-named functions in different classes. Since some kind of data-unpacking for each function individually is necessary anyways, we have individual unpacking-lambdas inside the map.
If a function's arguments are just the abstract data structure, i.e. const std::string&, we could leave the lambdas out and just do:
const FunctionMap<Cat> Cat::functionMap = {
{ "meow", &Cat::meow }
};
Which works by way of std::functions magic (passing this via the 1st argument), which, in contrast to function pointers, is well-defined and allowed. This would be particularly useful if all functions have the same signature. In fact, we could then even leave out the std::function and plug in Jarod42's suggestion.
PS: Just for fun, here's an example where casting a member-function-pointer to an function-pointer fails:
#include <iostream>
struct A {
char x;
A () : x('A') {}
void foo () {
std::cout << "A::foo() x=" << x << std::endl;
}
};
struct B {
char x;
B () : x('B') {}
void foo () {
std::cout << "B::foo() x=" << x << std::endl;
}
};
struct X : A, B {
};
int main () {
void (B::*memPtr) () = &B::foo;
void (*funPtr) (X*) = reinterpret_cast<void (*)(X*)> (memPtr); // Illegal!
X x;
(x.*memPtr) ();
funPtr (&x);
}
On my machine, this prints:
B::foo() x=B
B::foo() x=A
The B class shouldn't be able to print "x=A"! This happens because member-function pointers carry an extra offset that is added to this before the call, in case multiple inheritance comes into play. Casting loses this offset. So, when calling the casted function pointer, this automatically refers to the first base object, while B is the second, printing the wrong value.
PPS: For even more fun:
If we plug in Jarod42's suggestion:
template <typename C, void (C::*M)(), typename Obj>
void AsFunc (Obj* p) {
(p->*M)();
}
int main () {
void (*funPtr) (X*) = AsFunc<B, &B::foo, X>;
X x;
funPtr (&x);
}
the program correctly prints:
B::foo() x=B
If we look at the disassembly of AsFunc, we see:
c90 <void AsFunc<B, &B::foo, X>(X*)>:
c90: 48 83 c7 01 add $0x1,%rdi
c94: e9 07 ff ff ff jmpq ba0 <B::foo()>
The compiler automatically generated code that adds 1 to the this pointer, such that B::foo is called with this pointing to the B base class of X. To make this happen in the AsFunc function (opposed to buried within main), I introduced the Obj template parameter which lets the p argument be of the derived type X such that AsFunc has to do the adding.

const method modifies object using reference

The following code calls a const method passing a reference to a member, which is then modified.
#include <iostream>
struct A {
int i;
A(int _x) : i(_x) { }
void calc(int& j, const int value) const { j = value; }
void set1() { calc(i, 1); }
};
int main()
{
A a(3);
std::cout << a.i << std::endl;
a.set1();
std::cout << a.i << std::endl;
return 0;
}
The code compiles with gcc 6.4.0, and with clang 5.0.2, with no warnings.
Is the code legal?
The const method calc is able to modify the object, when called from a non-const method.
const qualifier on a member function applies to the *this instance.
In calc(), this is a pointer to const A, but the parameter j is taken by non-const reference, so this is perfectly standard behaviour.
Now, if in calc you tried to assign to this->i, the code would not compile.
void A::calc(const int value) const
{
i = value; // Compilation error here: i is a data member of a const instance
}
In the same way, if set1 was made a const member function, then, the code would not compile (because it would try to bind this->i to a parameter taken by non-const reference)
Sure. Marking the method const just makes *this const, i.e. the function promises not to modify the object by writing through this.
It's still possible to modify the object through other means (assuming they're not marked const as well, such as int& j in your example).
Remember that having a "const pointer" like const Thing* or a "const reference" like const Thing& does NOT mean that the const-qualified object cannot change while you have the pointer/reference. It only means that you can't use that particular pointer/reference as a way of changing it. But there could be other names, pointers, or references that do allow changing it.
A couple of examples:
void f1(const int& arg1, int& arg2) {
std::cout << "arg1 before: " << arg1 << "\n";
arg2 = 4;
std::cout << "arg1 after: " << arg1 << "\n"; // same thing?
}
f1 might look as though it must always print the same value in the "before" and "after" lines. But not if someone passes the same int object to both arguments:
void call_f1() {
int n = 7;
f1(n, n); // Prints before 7, after 4!
}
Or if a function call comes between two uses of a const reference, that can similarly change a variable in some way:
void something_else();
void f2(const int& arg) {
std::cout << "arg before: " << arg << "\n";
something_else();
std::cout << "arg after: " << arg << "\n";
}
int n = 2;
void something_else() { n = 8; }
void call_f2() {
f2(n); // Prints before 2, after 8!
}
So it's true that in your void A::calc(int& j, const int value) const function, the this pointer is const A* const, which means you can't change the A object using the this pointer. But there can still be other ways to change it, like here you have an int& j reference to non-const object. If it so happens that j refers to a subobject of *this, then modifying j is a valid way of modifying the subobject of *this. This is similar to my f1 example above, where arg1 can't be used to change the referenced int, but arg2 can, and if they refer to the same int, this means arg1 has changed.
The case is slightly different when a variable is defined with the const qualifier in the first place. If we write
const A a(3);
then we do get a guarantee that (except during the constructor and destructor), the object can't be changed in any way. The language will usually prevent you from accidentally trying, like with a.set1(), but even if you try const_cast tricks, any actual change would then be undefined behavior.
There is nothing wrong with your code. Declaring a method const merely means that this is const. However, your method does not (directly) modify this or any members of this. Consider this contrived, albeit correct example:
struct foo {
int value;
void modify_const(foo& f) const { f.value = 5; }
};
int main() {
foo f;
f.value = 3;
f.modify_const(f);
}
The method does not modify this, and the parameter is declared as non-const, thus calling f.modify_const(f); on a const f will fail due to the parameter being passed as non-const.
Just shows you are never safe. A const qualifier doesn't guarantee the value can never change.
Try it like this, and you can do really nasty things:
#include <iostream>
class A {
const int i;
void calc(int& j, const int value) const { j = value; }
public:
A(int _x) : i(_x) { }
void set1() const { calc(*const_cast<int*>(&i), 1); }
int getI() const { return i; }
};
int main()
{
const A a(3);
std::cout << a.getI() << std::endl;
a.set1();
std::cout << a.getI() << std::endl;
return 0;
}

How to pass variables (from Object of type Class) to functions (in the main.cpp) as an object only

I have a class(A) that contains for example five variables (parameters t,z,y,d and f) and I created an object(A) of a type class(A). Then I have many functions (X,U,M) that are included in the "main.cpp", each function is defined to take only three or four parameters that are already exist in the object(A). for example function(X) uses the variables (t,y and z only)
Instead of passing the parameters as void function(X) (int t, int y, double z){} can I pass only the object(A) and let each function selects its parameters by just looking for what it needs from object(A)'s parameters as follow (if this exist)?
void function(X) (A()){}
I would like to avoid using the following.
void function(X) (A.t, A.y, A.z){}
(Please note I am new to c++ and I am working in Qt Creator.)
Yes, you can pass an object to a function. There are several ways to pass the an instance of a class to a function:
by value (if function() needs to modify obj but the caller does not need to see the changes and copying is inexpensive):
void function(A obj) {}
by reference (if function() modifies obj and changes must be visible to the caller):
void function(A& obj) {}
by const reference (if function() does not modify obj):
void function(A const& obj) {}
by rvalue reference (c++11):
void function(A&& obj) {}
The class A will need to provide access to it's members.
Easy
class A
{
public:
double z;
};
void func(const A &obj)
{
// Do something with obj.z
std::cout << obj.z << std::endl;
}
int main()
{
A myObj;
myObj.z = 100;
func(myObj);
}
Joachim's explanation is what you need, except that the object should be passed as either a pointer or a reference, to ensure it isn't getting copied.
void someFunction(C& c)
// Accept a reference to a 'C' object
{
// Joachim's code
// This method doesn't change the main from Joachim's
// answer.
}
void someFunction(C* c)
// Accept a pointer to a 'C' object
{
std::cout << "The member i_ is " << c->getI() << std::endl;
// Note the use of '->', not '.' to access the object's method.
}
void main()
{
C c;
c.setI(1);
someFunction(&c);
// The '&' means 'address of' in this context. I.E. you're passing a pointer.
}
If the member fields are public you can access them from any function. If the are not public you have to add member functions to the class to get the values, so called "getter" functions.
#include <iostream>
class C
{
public:
int getI() const { return i_; }
void setI(const int i) { i_ = i; }
private:
int i_;
}
void someFunction(C c)
{
std::cout << "The member i_ in c is " << c.getI() << '\n';
}
int main()
{
C c;
c.setI(123);
someFunction(c);
}

non-resizeable vector/array of non-reassignable but mutable members?

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.