Trying to assign value to *this pointer fails - c++

I got this program in C++ and it works perfectly fine if I put last 2 lines in comment:
a = b;
MyAr c(b);
I tested it with a method that I deleted it. The problem is with the *this pointer I think, when I compile and run the program flashes for a moment and then disappears. Can you please help me? Thanks!
#include <iostream>
using namespace std;
class MyAr {
int *p;
int len;
public:
MyAr();
MyAr(int a);
MyAr(const MyAr& ob);
~MyAr();
MyAr& operator=(const MyAr& ox) { *this = ox; }
int& operator[](int i) { return p[i]; }
int length();
};
MyAr::MyAr() : p(0), len(0) {}
MyAr::MyAr(int a) : p(new int[a]), len(a) {}
MyAr::MyAr(const MyAr& ob) { *this = ob; }
MyAr::~MyAr() { delete p; }
int MyAr:: length(){
return len;
}
int main(){
MyAr a;
MyAr b(10);
for(int i=0; i< b.length(); ++i)
b[i] = i;
a = b;
MyAr c(b);
system("pause");
return(0);
}

The definition
MyAr& MyAr::operator=(const MyAr& ox) { *this = ox; }
is recursive, since the assignment *this = ox calls the overloaded assignment operator again. So you have infinite recursion (leading to the eventual termination of your program, presumably).
It's the same as calling the following function:
void f() { f(); }
Or, in English, you've defined the meaning of "assign from value ox" to be "assign from value ox", when what you really need to do is to define what it should mean in terms of the constituent structure of your type!
For example:
MyAr& MyAr::operator=(const MyAr& ox) {
delete [] a;
a = nullptr;
len = 0;
return *this;
}
(This may not have the semantics you desire; modify to taste.)

One of the most important things you will ever do in c++ is learn to write correct constructors and destructors:
#include <cassert>
#include <cstring>
#include <utility>
class MyAr {
int *p;
int len;
public:
MyAr() : p(nullptr), len(0) {};
MyAr(int a) : p(new int[a]), len(a) {};
// because we are overloading the destructor, rule of 3 is required (c++03)
MyAr(const MyAr& ob)
: p( nullptr), len(ob.len)
{
if (len) {
assert(ob.p);
p = new int[len];
std::memcpy(p, ob.p, len);
}
}
MyAr& operator=(const MyAr& r)
{
MyAr tmp(r);
swap(tmp);
return *this;
}
~MyAr() {
// note: delete []
delete [] p;
}
// or rule of 5 (c++11)
#if __cplusplus >= 201103L
MyAr(MyAr&& r)
: p(r.p)
, len(r.len)
{
r.p = nullptr;
r.len = 0;
}
MyAr& operator=(MyAr&& r)
{
auto tmp = MyAr(std::move(r));
swap(tmp);
return *this;
}
#endif
void swap(MyAr& other)
{
using std::swap;
swap(p, other.p);
swap(len, other.len);
}
int& operator[](int i) { return p[i]; }
int length();
};

Related

C++ pointer array moving

I am fairly new at the C/C++ pointer stuff, so I was wondering if this could cause any problems?
I got a class with a pointer array variable, which I would like to move along with the other variables in the move constructor. Can I just reasign its pointer, or is that a bad idea?
class C {
private:
char* a;
int size;
public:
C(int s)
{
size = s;
a = new char[s];
}
~C() noexcept
{
size = 0;
delete[] a;
}
C(const C& o): C(o.size)
{
std::copy(o.a, o.a + size, a);
}
C(C&& o) noexcept: size(o.size)
{
a = o.a;
o.a = nullptr;
}
C& operator=(const C& o)
{
if(this != &o)
{
char * l = new char[o.size];
size = o.size;
delete[] a;
a = l;
std::copy(o.a, o.a + size, a);
}
return *this;
}
C& operator=(C&& o) noexcept
{
if(this != &o)
{
delete[] a;
size = std::move(o.size);
a = o.a;
o.a = nullptr;
}
return *this;
}
};
Any feedback is welcome!
EDITS
Added move & assignment operator and copy constructor for complecity sake
Updated for full 'working' MVP
Why don't you use std::string and let the compiler do the work for you?
class C {
private:
std::string a;
public:
C() {}
}

Is it possible to use list like array?

I'd like to ask, Is it possible to make the list works like array?
I mean how to overload [] operator to make it work as in array.
I've read some kind of code. It's works for example when we want
-print memory cell : cout<<abc[0];
left-hand assignment of a variable : b = abc[0];
but does't work right-hand : abc[0] = 5;
and I'dont know how to determine the size of the array
#include <iostream>
#include <list>
#include <iterator>
using namespace std;
template<class type>
class My_array
{
public:
list<type> List;
void add(type element)
{
List.push_back(element);
}
void dele()
{
List.pop_back();
}
type operator [](int i)
{
typename list<type>::iterator iter;
int counter = 0;
for(iter = this->List.begin(); iter != this->List.end(); iter++)
{
if(counter == i) break;
counter++;
}
return *iter;
}
My_array &operator = (My_array &k)
{
if(this == &k) return *this;
return *this;
}
};
int main()
{
My_array<int> abc;
abc.add(5);
int b = 7;
cout<<abc[0]<<endl;
b = abc[0];
cout<<b<<endl;
return 0;
}
You can modify the overload to return a reference to the element.
type& operator [](int i) // add & to make it return a reference
Simply change
type operator [](int i)
to
type& operator [](int i)
It works for access and assignment!

How to solve error (projectname has triggered breakpoint)?

After I run the program I get an error saying projectname has triggered a breakpoint. I still do not know what the error is. I think there's a member function missing but someone help me out?
#include "AClass.h"
#include <iostream>
using namespace std;
int main()
{
AClass* x = new AClass(10, -1.0);
AClass y = *x;
delete x;
return 0;
}
Code from my cpp file is as follows:
#include "AClass.h"
#include <iostream>
using namespace std;
// Constructor
AClass::AClass(int len, double val)
: length(len)
{
if (len < 0) {
cout << "Invalid data length = " << len << endl;
data = NULL;
}
else {
data = new double[length];
for (int i = 0; i < length; i++)
data[i] = val;
}
}
// Destructor
AClass::~AClass()
{
// delete data if it is not NULL
if (data) delete[] data;
}
Your AClass member double* data; will be copied here:
AClass y = *x;
Since you haven't provided copy/move constructors/assignment operators, the raw pointer will be copied as-is in these situations and delete[] data will be done by both x and y in the destructor.
Mandatory read when dealing with raw pointers:
https://en.cppreference.com/w/cpp/language/rule_of_three
And these:
What is The Rule of Three?
Rule-of-Three becomes Rule-of-Five with C++11?
Here's an example implementation of the member functions mentioned in the above articles. It's a little much - and error prone, which is why it's almost always better to use a standard container.
#include <algorithm>
#include <iostream>
#include <utility>
class AClass {
public:
AClass(size_t len, double val);
// rule of five:
AClass(const AClass& rhs); // copy constructor
AClass(AClass&& rhs); // move constructor
AClass& operator=(const AClass& rhs); // copy assignment
AClass& operator=(AClass&& rhs); // move assignment
~AClass();
private:
size_t length; // use an unsigned type since you only accept unsigned values
double* data;
};
// destructor
AClass::~AClass() {
delete[] data;
}
AClass::AClass(size_t len, double val) :
length(len),
data(new double[length])
{
std::fill_n(data, length, val);
}
// copy constructor
AClass::AClass(const AClass& rhs) :
length(rhs.length),
data(new double[length])
{
std::copy_n(rhs.data, length, data);
}
// move constructor
AClass::AClass(AClass&& rhs) :
length(std::exchange(rhs.length, 0)),
data(std::exchange(rhs.data, nullptr))
{}
// copy assignment
AClass& AClass::operator=(const AClass& rhs) {
double* tmpdata = new double[rhs.length];
delete[] data;
length = rhs.length;
data = tmpdata;
std::copy_n(rhs.data, length, data);
return *this;
}
// move assignment
AClass& AClass::operator=(AClass&& rhs) {
// leave the destruction up to the moved-from object
std::swap(length, rhs.length);
std::swap(data, rhs.data);
return *this;
}
int main() {
AClass* x = new AClass(10, -1.0);
AClass y = *x;
delete x;
}

C++ operator syntax for handling a = b + c without making explicit copy of data in "a.data_ptr"

I would like to further exhaust this topic.
Assume that I have something like:
class MyClass
{
public:
MyClass(int N)
{
data_ptr = new float[N];
};
float* dat_ptr;
// ... clever operator definition here ...
};
So I would like to be able to simply write:
MyClass a(4);
MyClass b(4);
MyClass c(4);
// modify b.data_ptr and c.data_ptr ....
// Use "clever operator"
a = b + c;
Where the operator would do a.data_ptr[i] = b.data_ptr[i] + c.data_ptr[i] for i=0:(N-1) ...
Hence no extra copies of the data are created and we are neatly using the preallocated buffers.
Is this possible? If so, please provide me with som insights as to how it would be done.
Thanks!
You can, if you use move semantics from C++11.
class MyClass
{
public:
MyClass(int N)
{
data_ptr = new float[N];
n = N;
}
MyClass(MyClass && rhs)
{
data_ptr = rhs.data_ptr;
n = rhs.n;
rhs.data_ptr = nullptr;
}
// dtor, copy-ctor etc.
int n;
float * dat_ptr;
};
MyClass operator + (const MyClass & left, const MyClass & right)
{
MyClass result(left.n);
// Implement addition
}
// Note: no error-checking
This way a temporary object will be created, but the internal data will not be unnecessarily copied.
Read more about the move semantics.
It is not possible; Before a is assigned to, a temporary object will be created as a result of calling operator + (b, c); This operator should return the created instance, that should then be assigned to a; the created instance is always created by b + c.
What is possible though is to define += as a member operator and say:
b += c;
This would modify the value of b without creating extra copies.
Edit: I have reconsidered :)
You definitely can do it, by abstracting operations as lazy evaluation objects.
Here is an example:
class MyClass; // fwd. declaration of your class
struct LazySum
{
LazySum(const MyClass& a, const MyClass& b)
: x(a), y(b) {}
float operator[](int i) { return x[i] + y[i]; }
const MyClass& x;
const MyClass& y;
};
class MyClass
{
public:
MyClass(int N)
{
data_ptr = new float[n = N];
};
int n; // this shouldn't be public
float* dat_ptr; // nor this, but I went with your code
// ... clever operator definition here ...
MyClass& operator=(const LazySum& terms)
{
// ignore case when n != x.n or n != y.n
// because not the point of the example
// (and I'm lazy)
// sum evaluation occurs here
// with no new allocations
for(int i = 0; i < n; ++i)
data_ptr[i] = terms[i];
return *this;
}
};
LazySum operator=(const MyClass& x, const MyClass& y)
{
return LazySum(x, y); // LazySum is a couple of references in size
}
void client_code_using_clever_op()
{
MyClass a(4);
MyClass b(4);
MyClass c(4);
// modify b.data_ptr and c.data_ptr ....
// Use "clever operator"
a = b + c; // actual sum performed when operator = is executed
}
The idea is to store the terms, and perform late evaluation on the terms.
Points of improvement:
inject a functor in the construction of LazySum to make it become LazyOp (the functor would decide what the op is); Implement other binary operators on MyClass in terms of it.
use RAII in MyClass.
when you need to implement lazy evaluation operators on another type (e.g. some MyOtherClass) consider implementing LazyOp as a template on the terms and functor type.
this does not support more complex expressions without some extra work:
MyClass a(4), b(4), c(4), d(4);
d = (a + b) + c; // error
This example will not work because it would require an operator+(const LazySum&, const MyClass&);;
As Spook explained, yes it is possible. Just for fun I wrote a full example that you can compile and run. If a copy was to be created, you would get a message in the output. I tried this example in Visual Studio 2012 and runs fine.
class MyClass
{
private:
float *data_ptr;
std::size_t size;
public:
MyClass(std::size_t N = 0) :
size(N),
data_ptr(N ? new float[N]() : nullptr)
{}
MyClass(const MyClass& other) :
size(other.size),
data_ptr(other.size ? new float[other.size]() : nullptr)
{
std::copy(other.data_ptr, other.data_ptr + size, data_ptr);
std::cout << "Copy!" << std::endl;
}
MyClass(MyClass&& other)
{
size = 0;
data_ptr = nullptr;
swap(*this, other);
}
~MyClass()
{
delete[] data_ptr;
}
MyClass& operator=(MyClass other)
{
swap(*this, other);
return *this;
}
friend MyClass operator+(MyClass& first, MyClass& second)
{
MyClass result(std::min(first.size, second.size));
for (std::size_t i=0; i < result.size; i++) {
result.data_ptr[i] = first.data_ptr[i] + second.data_ptr[i];
}
return result;
}
friend void swap(MyClass& first, MyClass& second)
{
std::swap(first.size, second.size);
std::swap(first.data_ptr, second.data_ptr);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
MyClass a(5);
MyClass b(5);
MyClass c(5);
a = b + c; //this should not produce an extra copy
return 0;
}

overload operator[] on return type

There is something that is troubling my brain since a moment: I am trying to overload the [] operator based on the return type. Here is what I need to do:
class A {
private:
double* data_;
int N_;
public:
A (N=0):N_(N){
data_ = new double[N];
}
~A {delete[] data_;}
double operator[] (const int i) {
return data_[i];
}
double* operator[] (const int i) {
return &data[i]; // for example; in fact here i need to return some block of data_
}
};
This code won't compile; and that is my problem. Can someone help me to solve this problem?
PS: I know how to overload normal functions on the return type for example:
int foo ();
string foo ();
I used some tricks that I read in this forum. In this way:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
func(); // calls neither
}
Thank you.
Two method overloads must have different signatures. The return type is not part of the signature of a method.
You can use the same "trick" that you use for functions, that is use a proxy object with conversion operators:
class A
{
private:
double* data_;
int N_;
public:
A (int N = 0)
: N_(N), data_(new double[N])
{}
~A() { delete[] data_; }
struct proxy
{
int i;
double * data;
operator double() const
{
return data[i];
}
operator double*()
{
return &data[i];
}
operator double const *() const
{
return &data[i];
}
};
proxy operator[] (int const i) {
proxy p { i, data_ };
return p;
}
proxy const operator[] (int const i) const {
proxy p { i, data_ };
return p;
}
};
int main()
{
{
A a(12);
double d = a[0];
double * pd = a[0];
}
{
A const ca(12);
double d = ca[0];
//double * pd = ca[0]; // does not compile thanks to overloads on const
double const * pcd = ca[0];
}
}
However, I would argue that this is a terrible idea. Having your operator[] return either a value or a pointer to this value is guaranteed to confuse the users of your class, in addition to making it impractical to use in expressions where both types are possible. For instance, std::cout << a[0]; would not compile (ambiguous overloads).
Probably you need something like that:
class A {
private:
double* data_;
int N_;
... // other stuff
public:
double operator[] (const int i) const { // note const here
return data_[i];
}
double& operator[] (const int i) { // note reference here
return data_[i];
}
};
also operator should be public to have a sense.