Two operators simultaneity overload in c++ - c++

I want to represent my object like an array. I mean that the programmer can write in his code
myobject[3]=2
In the back (in myobject code) there isn't an array at all, it's only representation.
So I need to overload [] and = simultaneously.
How can this be done?
thank you,
and sorry about my poor English.

operator[] should return a reference to object you are trying to modify. It may be some kind of metaobject, that overloads operator= to do whatever you wish with your main object.
Edit: As the OP clarified the problem, there is a way to do this. Look here:
#include <vector>
#include <iostream>
int & func(std::vector<int> & a)
{
return a[3];
}
int main()
{
std::vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
func(a) = 111;
std::cout << a[3] << std::endl;
}

So I need to overload [] and = simultaneity. How can it's can be done?
It can't be done. What you can do instead is override operator[] to return a 'proxy reference'. That is, an object that has knowledge of the object 'myobject' to which it was applied and the index used '3', and provides appropiate conversion operators to the mapped type (I pressume int) as well as assignment operators. There are a few examples of proxy references in the standard library itself. Something in the lines of:
class proxy
{
public:
proxy( object& object, int index ) : _object( object ), _index( index ) {}
operator int() const { return _object.implementation.value_at( index ); }
proxy operator=( int value ){ _object.implementation.value_at( index, value ); return *this; }
private:
object& _object;
int _index;
};

#yoni: It is possible to give address of any member of the vector (as long as it exists). Here's how it's done.
int& MyObject::operator[](size_t index)
{
return mVector[index];
}
const int& MyObject::operator[](size_t index) const
{
return mVector[index];
}
This is possible because std::vector is guaranteed to be storing elements in a contiguous array. The operator[] of std::vector returns a reference-type of the value it stores. By you overloading the operator[], you just need to pass that reference out of your operator[] function.
NOTE: std::vector will take care of bounds check. With the solution that #Griwes gives, there's no bounds checking.
EDIT: Seems like Griwes has edited his solution.

Related

C++ Return temporary values and objects that cannot be copied

I know that references can extend the lifetime of a return value in C++. With this phylosophy, I tried the following: I have three clases, 'tensor', 'view' and 'mutable_view'. Operator () on a tensor returns a "const view" object. This view has a private copy constructor so that the view cannot be copied, as it keeps information about the tensor that might not survive beyond the current statement.
#include <iostream>
#include <algorithm>
struct tensor {
int data[10];
class view {
const int *const data;
view();
view(const view &);
public:
view(const int *new_data) : data(new_data) {}
int operator*() const { return *data; }
};
class mutable_view {
int *const data;
mutable_view();
mutable_view(const mutable_view &);
public:
mutable_view(int *new_data) : data(new_data) {}
void operator=(const view &v) {
*data = *v;
}
};
tensor(int n) {
std::fill(data, data+10, n);
}
const view operator()(int ndx) const {
return view(data + ndx);
}
mutable_view at(int ndx) {
return mutable_view(data + ndx);
}
};
int main()
{
tensor a(1);
tensor b(2);
b.at(2) = a(2);
for (int i = 0; i < 10; i++)
std::cout << "a[i] = " << b.data[i] << std::endl;
for (int i = 0; i < 10; i++)
std::cout << "b[i] = " << b.data[i] << std::endl;
exit(0);
}
The problem is that, while this code works in gcc (depends on the version), icc signals a warning and open64 simply does not build it: it demands that the constructors from 'view' be public. Reading icc's message the idea seems to be that the right hand value could be potentially copied by the compiler and thus constructors are needed.
Is this really true? Is there a workaround that preserves the syntax I want to build? By the way they are built, and in order to avoid inefficient implementations based on shared_ptr or other stuff, I need to keep the 'view' objects un-copiable.
Edit 1:
tensor cannot control the lifetime of the views. The views are created by the accessors and their lifetime is limited to the statement where they are used, for the following reasons:
These views are only used for two things: (i) copying data, (ii) extracting portions of the tensor.
The tensors are multidimensional arrays that implement copy-on-write semantics, which means that the views cannot be long-lived objects: if the data changes, they expire.
Edit 2:
Changed the pseudocode description (guys, if you see '...' do you expect it to be compilable?) with one that builds on 'icc' and does not on clang/open64
Go ahead and let the default copy constructors be public. And document that a view or mutable_view is "invalidated" when its tensor is changed or destroyed.
This parallels how the Standard Library deals with iterators, pointers, and references that have a lifetime which depends on another object.
As others already pointed out you missed () here:
const view operator(int ndx) const;
Anyway this declaration means that return value is copied. If you want to avoid copying just return reference for an object:
const view& operator()(int ndx) const;
As I understand 'tensor' is container of 'views' so it manages there lifetime and its safe to return reference. For the same reason tensor::at should return reference to mutable_view:
mutable_view& at(int ndx);
Another question is about default constructor of 'view' - it looks like 'tensor' has to be a friend of 'view' to be able to create its instances
By the way - prefer using 'size_t' as index type instead of just 'int'
My overall feeling of this code - you are trying to implement kind of domain language. Maybe it's better to focus on concrete calculation task?

std::find not using my defined == operator

I have a simple class that I am storing in a vector as pointers. I want to use a find on the vector but it is failing to find my object. Upon debugging it doesn't seem to call the == operator I've provided. I can 'see' the object in the debugger so I know its there. The code below even uses a copy of the first item in the list, but still fails. The only way I can make it pass is to use MergeLine* mlt = LineList.begin(), which shows me that it is comparing the objects and not using my equality operator at all.
class MergeLine {
public:
std::string linename;
int StartIndex;
double StartValue;
double FidStart;
int Length;
bool operator < (const MergeLine &ml) const {return FidStart < ml.FidStart;}
bool operator == (const MergeLine &ml) const {
return linename.compare( ml.linename) == 0;}
};
Class OtherClass{
public:
std::vector<MergeLine*>LineList;
std::vector<MergeLine*>::iterator LL_iter;
void DoSomething( std::string linename){
// this is the original version that returned LineList.end()
// MergeLine * mlt
// mlt->linename = linename;
// this version doesn't work either (I thought it would for sure!)
MergeLine *mlt =new MergeLine(*LineList.front());
LL_iter = std::find(LineList.begin(), LineList.end(), mlt);
if (LL_iter == LineList.end()) {
throw(Exception("line not found in LineList : " + mlt->linename));
}
MergeLine * ml = *LL_iter;
}
};
cheers,
Marc
Since your container contains pointers and not objects, the comparison will be between the pointers. The only way the pointers will be equal is when they point to the exact same object. As you've noticed the comparison operator for the objects themselves will never be called.
You can use std::find_if and pass it a comparison object to use.
class MergeLineCompare
{
MergeLine * m_p;
public:
MergeLineCompare(MergeLine * p) : m_p(p)
{
}
bool operator()(MergeLine * p)
{
return *p == *m_p;
}
};
LL_iter = std::find_if(LineList.begin(), LineList.end(), MergeLineCompare(mlt));
I think what you really want is to use std::find_if like this:
struct MergeLineNameCompare
{
std::string seachname;
MergeLineNameComp(const std::string &name) : seachname(name)
{
}
bool operator()(const MergeLine * line)
{
return seachname.compare( line->linename ) == 0;
}
};
LL_iter = std::find_if(LineList.begin(), LineList.end(), MergeLineNameCompare(linename) );
The operator == (no matter wich form) is better saved for real comparison of equality.
Operator overloading can't work with pointers as it is ambiguous.
Bjarne Stroustrup :-
References were introduced primarily to support operator overloading.
C passes every function argument by value, and where passing an object
by value would be inefficient or inappropriate the user can pass a
pointer. This strategy doesn’t work where operator overloading is
used. In that case, notational convenience is essential so that a user
cannot be expected to insert address− of operators if the objects are
large.
So, may be not best but still :-
std::vector<MergeLine>LineList;
std::vector<MergeLine>::iterator LL_iter;

C++ std::sort() Calling Destructor

I overloaded my class' () operator to use it as a sort comparer function. When using std::sort(), it for some reason calls the the class' destructor a bunch of times (dependant on the amount of entries in the vector, apparently). I've described more in ~RANK().
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
class RANK
{
struct COMBO
{
int x;
};
std::vector<COMBO *> data;
public:
RANK()
{
printf("RANK()\n");
}
~RANK()
{
printf("~RANK()\n");
/*
* Here is the problem.
* Since my vector consists of pointers to COMBO objects,
* I delete them upon RANK object's destruction. However,
* std::sort() calls RANK's destructor many times and
* throws some runtime error, unless commented out.
*/
//for (unsigned int i = 0, n = data.size(); i < n; i++)
// delete data[i];
}
void Add(int x)
{
COMBO *combo = new COMBO();
combo->x = x;
data.push_back(combo);
}
unsigned int Size()
{
return data.size();
}
void Sort()
{
std::sort(data.begin(), data.end(), *this);
}
int operator[](unsigned int pos)
{
return data[pos]->x;
}
bool operator()(COMBO *combo1, COMBO *combo2)
{
return combo1->x > combo2->x;
}
};
int main()
{
RANK rank;
rank.Add(1337);
rank.Add(9001);
rank.Sort();
for (unsigned int i = 0, n = rank.Size(); i < n; i++)
printf("%d ", rank[i]);
printf("\n");
system("pause");
return 0;
}
The output (with commented destructor):
RANK()
~RANK()
~RANK()
~RANK()
~RANK()
~RANK()
9001 1337
The comparison function to std::sort is passed by value. By using the RANK object as the comparator, you are passing a copy to std::sort (as the last value) and it may copy it more than once internally.
I would suggest separating out the comparison operator for COMBO from the class RANK
The first problem is that you're breaking the Rule of Three. Your class requires a non-trivial destructor to release its resources, so it needs to be either correctly copyable or uncopyable to avoid multiple objects owning the same resources. The simplest solution is to prevent copying by deleting the copy constructor and copy-assignment operator:
RANK(RANK const &) = delete;
void operator=(RANK const &) = delete;
or, if you're stuck with a pre-2011 compiler, declare them private with no implementation.
Alternatively, you could consider storing smart pointers such as std::unique_ptr (to prevent copying) or std::shared_ptr (to allow shared ownership); if you do that, then your class will have the same (safe) copy semantics as the pointer you choose.
Preventing copying will make the second problem obvious: you're using the RANK object as the comparator for std::sort. The comparator is taken by value, so the object is copied there. That's easy to fix by defining a separate type for the comparator:
struct CompareCOMBO {
bool operator()(COMBO *combo1, COMBO *combo2) {
return combol1->x > combo2->x;
}
};
std::sort(data.begin(), data.end(), CompareCOMBO());
or, if you can use lambdas:
std::sort(data.begin(), data.end(),
[](COMBO *combo1, COMBO *combo2){
return combo1->x > combo2->x;
}
);
Provide a copy constructor and place a breakpoint inside to see where it is called.
By passing *this as your compare object it gets copied during the sort (that's why you don't see the construction popping, if you had a copy constructor you would see calls to that).
Consider this thread to sort your objects

Operator Overloading: C++

I have a question about Operator Overloading in C++.
For an assignment, I have to write a class which encompasses an array, sort of like the ArrayList in Java.
One of the things I have to do is keep track of the size of the array. Size is the amount of elements included, whereas capacity is the maximum amount which CAN be included before the class has to expand the array.
Client code specifies the size when they call the constructor. However, when new elements are added, I have to figure out a way to change the size.
My teacher said something about being able to overload an operator for different sides of an equality. Is this a real thing, or did I misunderstand her? If this works, it would be the optimal solution to my problem.
My current overloading for the [] operator is:
int & ArrayWrapper::operator [] (int position){
if(position == _size){
if(_size == _capacity){
changeCapacity(_capacity+10);
}
}
return _array[position];
}
This works fine for retrieval, but I'd like to have it so that if someone calls it from the left hand side of a '=' then it checks to see if it needs to expand the size or not.
EDIT: If this isn't a real thing, can anyone think of a different solution to the problem? One solution I thought of is to have the getSize() method just go through the entire array every time it is called, but I'd really rather not use that solution because it seems cheesy.
EDIT: For clarification, I'm not asking whether or not my expansion of an array works. I need to add 1 to size every time a new element is added. For example, if the client creates an array of size 15 and capacity 25, and then tries to add something to Array[15], that SHOULD increase the size to 16. I was wondering if there was a way to do that with overloading.
A simple approach, which doesn't quite do what you want, is to overload on whether the array is const or mutable.
This doesn't distinguish between whether the array is being used on the left-hand side of assignment (as a lvalue) or on the right (as a rvalue); just on whether it's allowed to be modified or not.
// Mutable overload (returns a mutable reference)
int & operator[](size_t position) {
if (position >= _size) {
if (position >= _capatity) {
// increase capacity
}
// increase size
}
return _array[position];
}
// Const overload (returns a value or const reference)
int operator[](size_t position) const {
if (position >= _size) {
throw std::out_of_range("Array position out of range");
}
return _array[position];
}
If you really want to tell whether you're being assigned to or not, then you'll have to return a proxy for the reference. This overloads assignment to write to the array, and provides a conversion operator to get the value of the element:
class proxy {
public:
proxy(ArrayWrapper & array, size_t position) :
_array(array), _position(position) {}
operator int() const {
if (_position >= _array._array._size) {
throw std::out_of_range("Array position out of range");
}
return _array._array[_position];
}
proxy & operator=(int value) {
if (_position >= _size) {
if (_position >= _capatity) {
// increase capacity
}
// increase size
}
_array._array[_position] = value;
return *this;
}
private:
ArrayWrapper & _array;
size_t _position;
};
You probably need to declare this a friend of ArrayWrapper; then just return this from operator[]:
proxy ArrayWrapper::operator[](size_t position) {
return proxy(*this, position);
}
This approach is fine. There's an error in the code, though: what happens if someone calls that operator with a position that's equal to the current size of the array plus 100?
The question is whether you really want different behavior depending on
which side of the = you are. Your basic idea will work fine, but will
expand the array regardless of the side you're on, e.g.:
ArrayWrapper a(10);
std::cout << a[20] << std::end;
will result in expanding the array. Most of the time, in such cases,
the preferred behavior would be for the code above to raise an exception,
but for
ArrayWrapper a(10);
a[20] = 3.14159;
to work. This is possible using proxies: first, you define double
ArrayWrapper::get( int index ) const and void ArrayWrapper::set( int
index, double newValue ); the getter will throw an exception if the
index is out of bounds, but the setter will extend the array. Then,
operator[] returns a proxy, along the lines of:
class ArrayWrapper::Proxy
{
ArrayWrapper* myOwner;
int myIndex;
public:
Proxy( ArrayWrapper& owner, int index )
: myOwner( &owner )
, myIndex( index )
{
}
Proxy const& operator=( double newValue ) const
{
myOwner->set( myIndex, newValue );
}
operator double() const
{
return myOwner->get( myIndex );
}
};
In case you're not familiar with the operator double(), it's an
overloaded conversion operator. The way this works is that if the
operator[] is on the left side of an assignment, it will actually be
the proxy which gets assigned to, and the assignment operator of the
proxy forwards to the set() function. Otherwise, the proxy will
implicitly convert to double, and this conversion forwards to the
get() function.

defining operator [ ] for both reading and writing

In the book of "The C++ Programming Language", the author gave the following example along with several statements:
Defining an operator, such as [], to be used for both reading and writing is difficult where it is not acceptable simply to return a reference and let the user decide what to do with it.
Cref, is to help implement a subscript operator that distinguishes between reading and writing.
Why [] is difficult to be defined when to be used for both reading and writing?
How does the definition of class Cref help to solve this issue?
class String{
struct Srep;
Srep *rep;
public:
class Cref;
// some definitions here
void check (int i) const { if (i<0 || rep->sz<=i) throw Range( );}
char read( int i) const {return rep->s[i];}
void write(int i, char c){ rep=rep->get_own_copy(); rep->s[i]=c;}
Cref operator[] (int i){ check(i); return Cref(*this, i);}
char operator[] (int i) const{check(i); return rep->s{i];}
}
class String::Cref{
friend class String;
String& s;
int i;
Cref(String& ss, int ii): s(ss),i(ii) {}
public:
operator char( ) { return s.read(i);}
void operator=(char c){s.write(i,c);}
};
If you don't define a class Cref that solves this issue, then you have to do what std::map does:
template class <K,V> class map{
V& operator[](K const & key);
}
This returns a reference, which must be backed by a valid memory location, and therefore
std::map<string,string> m;
m["foo"];
assert(m.find("foo") != m.end());
The assertion will succeed (meaning, "foo" is now a valid key in the map) even though you never assigned something to m["foo"].
This counterintuitive behavior can be fixed by the Cref class in your example -- it can perform the appropriate logic to create m["foo"] only when you assign to the reference, and ensure that m.find("foo") == m.end() if you didn't perform some assignment when you tried to read the nonexistant m["foo"].
Likewise, in your String class (which is a reference-counted string -- strings share their string data, and a new copy is created when you change a string whose data is shared with another string), you'd have to make a copy when using operator[] to read characters. The use of the Cref class, allows you to ensure that you only make a copy when using operator[] to write.
String s;
s[0] = 5;
will call String::operator [](int) and then String::Cref::operator =(char).
However,
String s;
char c = s[0];
will call String::operator [](int) and then String::Cref::operator char().
When reading, String::Cref::operator char is called, and when writing String::Cref::operator = is called - this allows you to distinguish between reading and writing.
Why [] is difficult to be defined when to be used for both distinguish between reading and writing?
It's because the non-const operator[] is called whenever you have a non-const object, even if you're using it in a read-only fashion.