how to overload assignment operator on class member variable - c++

I am trying to track the value of a variable that I will input in an API function.
One option is to overload the assignment operator and put some code there. But how would I overload an assigment operator on a member variable of a class?
#include <iostream>
using namespace std;
template <class T>
class MonitoredVariable1
{
public:
MonitoredVariable1() { }
MonitoredVariable1(const T& value) : m_value(value) {}
operator T() const { return m_value; }
T val;
T& operator = (const T& value)
{
val = value;
m_value = value;
std::cout << "value updated" << " \n"; //THIS NEVER GET PRINTED!!!
return val;
}
private:
T m_value;
};
int main()
{
MonitoredVariable1<double> MonitoredVariable;
MonitoredVariable.val = 10.2;
std::cout << "main done..." << " \n";
return 0;
}

To monitor changes to the variable, you need to be assigning to the class, not the contained variable.
First, get rid of val. Only have the private m_value value. This way all accesses have to go thru your member functions that can track the changes.
operator= should return a reference to the class (return *this;), not the value.
Assignment is to the class object:
MonitoredVariable = 10.2;

You can only overload assignment on a class. But you can make that variable to be of a class type with overloaded assignment, like:
class Monitor {
class Monitored {
double x;
public:
Monitored &operator= (double v) {
std::cout << "Assigned " << v << std::endl;
x = v;
return *this; // don’t forget this!
}
operator double() const {
std::cout << "Accessed " << x << std::endl;
return x;
}
};
Monitored val;
};
You may need to overload more operators, and also to pass a reference to Monitor into val (there are tricks to calculate it instead if you’re short on memory).
You can (in modern C++) even overload the & operator, but unless the API function is a template, it has to return pointer. Watching for access through it is very environment-specific.
During debugging, you can usually set a memory watchpoint that will pause program execution on writing to, or even on reading from, a particular memory location (for GDB, see Setting Watchpoints; VS should have a similar feature). That requires hardware support (or debugger-interpreter which is insanely slow), though, so the overall number of watchpoints is often very limited.
Without a debugger, you may be able to make a one-shot watch using memory protection tricks (like protecting the page containing the variable, and unprotecting it on first SEGV) but that’s all too fragile for normal use.

Related

Deducing type from template class conversion operator

I'm debugging an issue in a large C++ codebase where an attribute of a struct is occasionally being changed to a bad value. Unfortunately, the attribute is public and is accessed or changed in hundreds of places, so simply adding a breakpoint on a mutator is not possible. Also, I don't know the instance of the struct, so adding an address watchpoint wouldn't help.
Instrumenting the code would be a major job. However, a colleague helpfully suggested creating a proxy class which could wrap the existing type in the struct declaration. For example, instead of using MyType _type I would replace this with ChangeProxy<MyType> _type in the struct and the application should compile and work with the proxy taking the place of the direct type in the same manner as, for example, a smart pointer.
However, when I build an example, the implicit conversion operation in the template class doesn't appear to get invoked in type deduction. Here's the code:
#include <iostream>
class MyType {
long _n = 0;
public:
MyType() {}
MyType(const long n) : _n{n} {}
MyType& operator=(const long n) { _n = n; return *this; }
bool isZero() const { return _n != 0; }
};
template <class T>
class ChangeProxy {
public:
ChangeProxy() {}
ChangeProxy(const T& t) : _t{t} {}
ChangeProxy(const T&& t) : _t{std::move(t)} {}
ChangeProxy& operator=(const T& t) {onChange(t); _t = t; return *this;}
ChangeProxy& operator=(const T&& t) {onChange(t); _t = std::move(t); return *this;}
operator T() {return _t;}
private:
T _t;
void onChange(const T& newVal) { /* something here to notify me of changes */ };
};
struct MyStruct {
// MyType _type; // this works ...
ChangeProxy<MyType> _type; // .. but this doesn't
};
int main() {
MyStruct i;
std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
i._type = 1;
std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
return 0;
}
Unfortunately, when I build this I get the following errors:
proxy-variable~test.cpp:35:73: error: ‘class ChangeProxy<MyType>’ has no member named ‘isZero’
35 | std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
| ^~~~~~
proxy-variable~test.cpp:37:73: error: ‘class ChangeProxy<MyType>’ has no member named ‘isZero’
37 | std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
| ^~~~~~
So it seems that the compiler isn't deducing that it can cast a ChangeProxy<MyType> to a MyType. What have I done wrong here?
The context here doesn't let the compiler try out implicit conversions. Calling a member function on some object never does. You can force this by e.g.
std::cout << "i._type.isZero() : " << std::boolalpha <<
static_cast<MyType>(i._type).isZero() << '\n';
// ^^^^^^^^^^^^^^^^^^^ Here, enforce conversion
Another option would be:
MyStruct i;
const MyType& underlying = i._type; // Again, request conversion manually
std::cout << underlying.isZero() << '\n';
What you are doing is invoking a method on the class ChangeProxy<MyType> which indeed doesn't have any method isZero() defined on it, hence the compilation error. You could probably add something like
T const& operator()() const {return _t;}
And then call it using
i._type().isZero()
The reason that the wrapped i._type.isZero() can never work is that implicit conversions of the i._type object aren't considered for direct method calls, and you can't overload operator. like you can operator->.
It's nothing to do with type deduction, there's simply no mechanism in the language to do what you want.
Luckily, you're solving the wrong problem anyway.
... a colleague helpfully suggested creating a proxy class which could wrap the existing type in the struct declaration
Hmm, you didn't mention that here - or am I a colleague now?
an attribute of a struct is occasionally being changed to a bad value
Which attribute? Be specific!
In your code, you're treating the MyType instance as the problematic attribute. However, the only state in MyType is its long _n member.
Writing
class MyType {
ChangeProxy<long> _n = 0;
which is what I actually suggested when I referred to wrapping built-in types, avoids this problem entirely. You may of course need operator!= to make isZero work, but that's a normally overloadable operator.
Oddly the code in your question doesn't permit any mutation of _n anyway, so it's unclear how it can be getting a bad value. However, I assume this is just an artefact of a simplified example.

Unable to dereference pointer

I am writing an implementation of the Haskell Maybe Monad in C++11.
However I got stuck when I tried to test the code. When I construt a value of the type with the pseudo constructor Just and then try to evaluate it with using the function fromJust (that should just "unpack" the value placed inside the Maybe) the program stops and eventually terminates silently.
So i tried to debug it; here is the output for the code of testMaybe.cpp:
c1
yeih2
value not null: 0xf16e70
I added a couple of print statements to evaluate where the program stops, and it seems to stop at the exact point where I dereference the pointer to return the value. (I have marked it in the code.)
At first I thought that the value in the maybe might have been deconstructed by the time i want to dereference the pointer, which, to my understanding, would result in undefined behaviour or termination. However, I was unable to find the place where that would have happened.
Can you please give me a hint on why this is happening?
testMaybe.cpp:
#include<iostream>
#include "Maybe.hpp"
using namespace std;
using namespace Functional_Maybe;
int main() {
Maybe<string> a{Maybe<string>::Just("hello") };
if(!isNothing(a)) cout << "yeih2 " << fromJust(a) << endl;
return 0;
}
Maybe.hpp
#pragma once
#include<stdexcept>
#include<iostream>
using namespace std;
namespace Functional_Maybe {
template <typename T>
class Maybe {
const T* value;
public:
Maybe(T *v) : value { v } {} //public for return in join
const static Maybe<T> nothing;
static Maybe<T> Just (const T &v) { cout << "c1" << endl; return Maybe<T> { new T(v) }; }
T fromJust() const {
if (isNothing()) throw std::runtime_error("Tried to extract value from Nothing");
cout << "\nvalue not null: " << value << " " << *value << endl;
// ^ stops here
return *value;
}
bool isNothing() const { return value==nullptr; }
~Maybe() { if (value != nullptr) delete value; }
};
template <typename T>
bool isNothing(Maybe<T> val) {
return val.isNothing();
}
template <typename T>
T fromJust(Maybe<T> val) {
return val.fromJust();
}
}
You class template Maybe owns resources (the dynamically allocated T), but does not follow the Rule of Three: the (implicitly defined) copy and move operations do shallow copies only, which leads to use-after-free and double-free problems. You should either implement proper copy and move operations (cosntructors and assignment operators) for your class, or use std::unique_ptr<const T> as the type of value, and remove your manual destructor (thereby following the preferred Rule of Zero).
Side note: have you looked into std::optional (or, in pre-C++17 versions, boost::optional)? They seem to be doing something very similar (or even identical) to your proposed class, and you might want to use them instead (or use them internally in your class if that suits you better). They might even be more efficient, using small object optimisation to avoid dynamic memory allocation in some cases.

C++ return reference variable in prefix overloading

I am confused when all the code I find shows returning a reference variable when overloading the prefix operator. I went through the parashift.com FAQ (http://www.parashift.com/c++-faq-lite/operator-overloading.html#faq-13.14) and it isn't clear, even though it says it WILL be clear when you read it. I adapted their example into a nonsensical, pointless little program to test.
#include<iostream>
using namespace std;
class Number {
public:
Number& operator++ (); // prefix ++
Number operator++ (int); // postfix ++
int value() { return value_; }
void setValue(int value) { value_ = value; }
private:
int value_;
};
Number& Number::operator++ () {
++value_;
return *this;
}
Number Number::operator++ (int unused) {
Number temp;
temp.setValue(value_);
++value_;
return temp;
}
int main()
{
Number someNum;
someNum.setValue(20);
cout << "someNum : " << someNum.value() << "\n";
someNum++;
++someNum;
cout << "someNum : " << someNum.value() << "\n";
return 0;
}
The problem is, it works if I just declare it as a Number object as well like so:
#include<iostream>
using namespace std;
class Number {
public:
Number operator++ (); // prefix ++
Number operator++ (int); // postfix ++
int value() { return value_; }
void setValue(int value) { value_ = value; }
private:
int value_;
};
Number Number::operator++ () {
++value_;
return *this;
}
Number Number::operator++ (int unused) {
Number temp;
temp.setValue(value_);
++value_;
return temp;
}
int main()
{
Number someNum;
someNum.setValue(20);
cout << "someNum : " << someNum.value() << "\n";
someNum++;
++someNum;
cout << "someNum : " << someNum.value() << "\n";
return 0;
}
I assume I simply need a better understanding of reference variables. Can anyone explain simply why the prefix operator SHOULD be coded as returning a reference variable?
The difference between :
Number& Number::operator++ () {
++value_;
return *this;
}
and
Number Number::operator++ () {
++value_;
return *this;
}
is that, when you use the first code, the following expression:
++(++(++someNum));
increments someNum THRICE. See the output here: http://ideone.com/y9UlY
However, when you use the second one, this
++(++(++someNum));
increments someNum just ONCE!! See the output here: http://ideone.com/eOLdj
It is because when you return the reference from operator++(), the second and third ++ invokes on the same object called someNum and therefore, it increments the same object, all the times. But when you return by value, the second and third ++ invokes on the temporary object which you returned from operator++(). Hence, the second and third call doesn't increment someNum, instead it increments the temporary objects which get destroyed at the end of the expression.
Now if the temporary objects get destroyed, why create then in the first place? After all, its pre-increment operator, which means the temporary and the original object will have the same value. So the good design decision is, return by reference when defining pre-increment operator, to avoid creating temporary, and improve performance.
First, there's an efficiency issue. You are creating a new instance of the class in order to return it for no reason.
Second, there's the semantic issue. Your code invokes the empty constructor or the copy constructor to make the temporary and then destructs the temporary. If that has semantic meaning that's inappropriate, then the code doesn't really work, it just appears to.
Third, the code returns the wrong thing. Consider: ++foo.do_something();. With your code, we call 'do_something' on the temporary object. We wanted to call do_something() on the pre-incremented foo.

Some troubles with C++ template pointer-to-member based property realization

My target was to make properties in C++ like in C# - with non-trivial set/get behavior.
Here, object of Property holds refs to master of the prop and its set/get methods.
Realisation, content of Property.h:
#include <iostream>
using namespace std;
namespace First {
template <class Master, class Type>
struct Property
{
Master &master;
const Type (Master::*&get) () const;
Type (Master::*&set)(Type value);
Property
(
Master &master,
const Type (Master::*get) () const,
Type (Master::*set)(Type value)
):
get(get),
set(set),
master(master)
{ }
operator const Type() const { cout << "inside" << endl; return (master.*get)(); }
Type operator = (Type value)
{
return (master.*set)(value);
}
};
// Test chamber.
class R
{
float x;
const float getx() const { cout << "returning " << 0 << endl; return 0; }
float setx(float value) { cout << "setting " << value << " in place of " << x << endl; return x = value; }
public:
Property<R, float> X;
R(): X(*this, &R::getx, &R::setx) { }
};
}
I also created .cpp file:
#include "Property.h"
using namespace First;
int main()
{
R r;
r.X = 10;
float y = r.X;
}
The program makes "assign" step, printing 'setting 0 to 10', but segfaults on call to "retrieve" step, no difference what code (or no at all) inside 'R::getx()'.
~/Sources$ ./a.out
setting 10 in place of 0
inside
zsh: segmentation fault ./a.out
It seems that call to (master.*get()) itself causes a failure. What is wrong in this code?
UPD: A tested out that any other call to master's functions leads to segfault, only one call of (master.*set) successes. Seems that this call invalidates state of object, member-to-ptr, Property itself or Moon phase.
const Type (Master::*&get) () const;
Type (Master::*&set)(Type value);
Remove & from the above definitions. Because of &, each of these bound to the constructor parameters which do not exist after the constructor returns.
Also note that it seems that (master.*set)(value) works, its because you're unlucky. Its actually invokes undefined behavior. But you're lucky that very soon you come to know the problem when (master.*get)() fails, giving segfault.
Use:
const Type (Master::*get) () const;
Type (Master::*set)(Type value);
It should work now, without any problem, as it would cause copy of the addresses in the initialization-list, rather than referring to the parameters!
segfault : http://ideone.com/46RrU (your original code)
no fault : http://ideone.com/PljI4 (after fixing)

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.