First things first, I have the below class A which at the same time have a nested class B:
// A.h
class A {
public:
class B;
A();
A(const A& a); // Copy constructor
B& operator[](const unsigned int& a) const;
A operator+(const A& a) const;
/*...*/
~A();
private:
/*...*/
unsigned int size;
B* b;
};
and I'm trying to use the overloaded + operator to "add" two A objects by adding the content of both b members of said objects, and assign the result to a third A object.
b is a dinamically allocated array of B objects.
B is a pretty basic class with just some unsigned int
here's the main function:
// main.cpp
int main(int argc, char** argv) {
A a1, a2, result;
a1.read(argv[1]); // Initialize b member with content read from a file
a2.read(argv[2]); // Initialize b member with content read from a file
result = a1 + a2; // Error [3]
getchar();
return 0;
}
The problem is that when trying to make the sum I get what I think are memory errors like: HEAP[main.exe]: Invalid address specified to RtlValidateHeap( 00A50000, 00A59938 )
here's the implementation of class A:
// A.cpp
A::A() : /*...*/, size(0), b(nullptr) {}
// Copy constructor
A::A(const A& a) : /*...*/, size(a.size), b(nullptr) {
b = new B[size]; // [1]
for (unsigned int i = 0; i < size; i++) {
(*this)[i] = a[i];
}
}
A::B& A::operator[](const unsigned int& i) const {
return b[i];
}
A A::operator+(const A& a) const {
if (size != a.size) {
exit(1); // Size must be the same on both operands
}
A tmp(*this); // Call to copy constructor
for (unsigned int i = 0; i < a.size; i++) {
tmp[i] += a[i];
}
return tmp; // Call to copy constructor [2]
}
A::~A() {
if (b != nullptr) {
delete[] b;
}
}
and of class B:
// B.h
class A::B {
public:
B();
B(unsigned char, unsigned char, unsigned char);
B& operator+=(const B& b);
private:
unsigned int a, b, c, d;
};
// B.cpp
A::B::B() : a(0), b(0), c(0), d(0) {}
A::B::B(unsigned char _a, unsigned char _b, unsigned char _c) {
/*...*/
}
A::B& A::B::operator+=(const B& b) {
/*...*/
return *this;
}
I'm using Visual Studio by the way, and when debugging I've observed:
b member of result points to the same address pointed by b in [1] when the copy constructor is called by the return statement in [2], so far so good
Until the return in [2] the content of b is all right, something like: 0x00669968 00 00 ff 00 00 ff 00 00 ..ÿ..ÿ..
After [3] the content of b in [1] and therefore the content of b member of result object becomes something like: 0x00669968 dd dd dd dd dd dd dd dd ÝÝÝÝÝÝÝÝ, I'm guessing is garbage
Note: all include directives and irrelevant sections of code have been ommited
I've been like two days shaking my head trying to figure out what's wrong with no luck so any help is greatly appreciated, thanks in advance.
I check your code and the problem is that you need a custom copy assignment for class A. In your main you have A a1, a2, result;, the default constructor is called for the 3 objects. Then, in the line result = a1 + a2;, the default copy assignment is called.
When you have pointers in your class and allocate the memory using new then you have to worry about copy constructor and copy assignment. Check this post and the rule of three.
I propose you the next code:
class A {
class B {
unsigned a, b, c, d;
public:
B() : a(0), b(0), c(0), d(0) { }
B(unsigned char a_, unsigned char b_, unsigned char c_) : a(a_), b(b_), c(c_), d(0) { }
// Copy constructor.
B& operator=(const B& b_) {
a = b_.a;
b = b_.b;
c = b_.c;
d = b_.d;
return *this;
}
B& operator+=(const B& b_) {
a += b_.a;
b += b_.b;
c += b_.c;
d += b_.d;
return *this;
}
};
unsigned size;
B* b;
public:
A() : size(0) { }
// Copy constructor.
A(const A& a) : size(a.size) {
b = new B[size];
for (unsigned i = 0; i < size; ++i) {
b[i] = a[i];
}
}
// Copy assigment
A& operator=(const A& a) {
clear();
b = new B[size];
for (unsigned i = 0; i < size; ++i) {
b[i] = a[i];
}
return *this;
}
B& operator[](unsigned pos) const {
if (pos > size) {
throw std::out_of_range("Out of range");
}
return b[pos];
}
A operator+(const A& a) const {
A tmp = *this;
if (size != a.size) {
throw std::out_of_range("Diferent sizes");
}
for (unsigned i = 0; i < a.size; ++i) {
tmp[i] += a[i];
}
return tmp;
}
void read(const char* file) {
clear();
size = size_;
b = new B[size];
/*
* Read your file and update b.
*/
}
void clear() {
if (size) {
delete[] b;
size = 0;
}
}
~A() {
clear();
}
};
Related
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() {}
}
I've looked around and only found a solution for either problem, which conflicts with the other.
I have
class A with some const member and other members that need to be initialized
class B with some constructor and a 2D array of A's
like this:
class A {
public:
A();
A(int t, int u);
const int x = 5;
private:
int _t;
int _u;
}
class B {
public:
B();
A a[50][500];
}
A::A() {
//nothing here
}
A::A(int t, int u) {
_t = t;
_u = u;
}
B::B() {
for (int i=0; i<50; i++)
for(int j=0; j<500; j++)
a[i][j] = A(i, j);
}
Now, this doesn't work because A has a const member, so the assignment fails because all the a's have already been default constructed, I obviously don't want to code 25000 initializer values in the member initializer list of B so that is out of the question.
I need the default initializer because otherwise the constructor of B will throw an error that i can't default initialize the array so i need some way to reassign the array with a newly constructed object of A.
How could I accomplish this?
This is what you want?
class A {
public:
A();
A(int t, int u);
const int x = 5;
A& operator=(const A& a);
private:
int _t;
int _u;
};
class B {
public:
B();
A a[50][500];
};
A::A() {
//nothing here
}
A& A::operator=(const A& a) {
_t = a._t;
_u = a._u;
}
A::A(int t, int u) {
_t = t;
_u = u;
}
B::B() {
for (int i=0; i<50; i++)
for(int j=0; j<500; j++)
a[i][j] = A(i, j);
}
You are just missing the = operator
If you want to avoid default-initializing your array, you can use std::vector<std::vector<A>> and populate it in B's constructor :
class A {
public:
A(t, u);
const int x = 5;
private:
int _t;
int _u;
}
class B {
public:
B();
std::vector<std::vector<A>> a;
}
A::A(t, u) {
_t = t;
_u = u;
}
B::B()
: a(50) { // a will contain 50 empty rows
for (int i=0; i<50; i++) {
a[i].reserve(500); // allocates enough space in each row for at least 500 elements
for(int j=0; j<500; j++)
a[i].emplace_back(i, j); // constructs value in-place using given arguments
}
}
Note that you don't need A's empty-parameter constructor anymore, so I have removed it.
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();
};
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;
}
I have the next classes.
in the main I have 2 kinds of assignments operator (A=A and B=B).
I'm trying to get the main working, so I tried:
class A { // assume that this class is abstract
public:
virtual void assignment(const A& num) = 0;
void operator=(const A& num) { assignment(num); }
void func() = 0; // the class is abstract
};
class B: public A {
int i;
public:
void assignment(const B& num) { i = num.i; }
B& operator=(const B& num) { i = num.i; }
void func() { cout << "hello!\n"; }
};
int main()
A* a1 = new B(7); //assume I have it
A* a2 = new B(6); //assume I have it
B b1(2);
B b2(4);
*a1 = *a2; // implement an assignment operator
b1 = b2; // implement an assignment operator
}
but I got some errors that tell me that B is an abstract class and then the copy constructor doesn't work
any help appreciated!
Ok, now I see what the problem is:
void assignment(const B& num) { i = num.i; }
should be:
void assignment(const A& num) { ... }
However, we now have a problem: num which is of type A does not have a member variable i. So we need to ensure that num is actually of class B. The ... part in the above now turns into:
B& b_num = dynamic_cast<B&>(num);
i = num.i;
Note however that dynamic_cast may throw an exception if you are trying to convert some other type to B& than B.