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;
}
Related
I am new to C++, and I am trying to return the struct declared within a class via char*.
#include<iostream>
using namespace std;
#include <cstring>
class test
{
public:
struct pair
{
int a,b;
};
test(){
pir=new pair;
pir->a=1;
pir->b=2;
}
void readx(char* str)
{
char* str2=new char[sizeof(pair)+1];
str2=reinterpret_cast<char*>(pir);
strncpy(str,str2,sizeof(pair));
}
private:
pair* pir;
};
int main()
{
test t;
char* ptr;
t.readx(ptr);
cout<<*((int*)ptr)<<endl;
cout<<*((int*)ptr+4)<<endl;
return 0;
}
I have tried multiple ways but still failed to return a char* that can be reinterpreted into the struct. Actually the returned char* can only hold the first parameter, losing information about the second parameter, despite that I have used strncpy function. The output of this test code is
1
0
How could I return the everything about struct within the class?
cout<<*((int*)ptr+4)<<endl;
This line should be:
cout<<*((int*)ptr+1)<<endl;
Because you have convert ptr to int *, which +1 means move pointer to next 4 bytes (size of int is 4).
You've got serious problems with your code. If it's really working, it's working only by accident.
Whether it's strncpy or memset you use it doesn't matter too much because you are passing unitialized pointer to the functions which writes to it:
char* ptr;
t.readx(ptr);
Where does ptr point to? It may point almost anywhere and using it as memcpy target is unpredictable. If you are not very unlucky, you will get a segfault/access violation.
Your readx method does some crazy thing:
char* str2 = new char[sizeof(pair)+1];
str2 = reinterpret_cast<char*>(pir);
Here you first alocate some storage and assign its address to str2 then you re-assign it to address of pir. You can never delete[] memory allocated by new[] so you introduce a memory leak.
Constructor of class test allocates memory using new but you don't have corresponding destructor calling delete -> memory leak.
Then there is your ptr+4 problem which was already pointed by the others. Here you can find the code corrected to the point where you can expect it to do what you want.
#include <iostream>
#include <cstring>
using namespace std;
class test
{
public:
struct pair
{
int a, b;
};
test() : pir{ new pair() }
{
pir->a = 1;
pir->b = 2;
}
~test() { delete pir; }
void readx(char* str)
{
memcpy(str, reinterpret_cast<char*>(pir), sizeof(pair));
}
private:
pair* pir;
};
int main()
{
test t;
char* ptr = new char[sizeof(test::pair)];
t.readx(ptr);
cout << *((int*)ptr) << endl;
cout << *((int*)ptr + 1) << endl;
delete[] ptr;
return 0;
}
When you understand the basic issues your code have read about the rule of five. For the test class you would add something like this:
#include <algorithm>
class test
{
//...
test(test const& other) : pir{ new pair() }
{
pir->a = other.pir->a;
pir->b = other.pir->b;
}
test& operator=(test const& other)
{
test copy(other);
swap(*this, copy);
return *this;
}
test(test&& other) noexcept : pir{ nullptr }
{
swap(*this, other);
}
test& operator=(test&& other) noexcept
{
swap(*this, other);
return *this;
}
friend void swap(test& lhs, test& rhs)
{
std::swap(lhs.pir, rhs.pir);
}
};
You are incrementing the int pointer by 4. This points 4 integers ahead. That's not what you want.
cout<<*((int*)ptr+1)<<endl;
That should get you b.
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 have a question regarding how the destructor is called. For example, I created the following foo class and supplied with copy constructor, destructor and overloaded the assignment operator. I created a dynamic array of this foo objects and used the operator "=" to assign individual element of the array. I am very confused, immediately after the assignment operation, the destructor is called and when I want to access the data in the newly assigned object, I got very confusing result.Any suggestions?
#include <iostream>
using namespace std;
bool debug = true;
class foo{
private:
int n;
void init(int _n);
public:
int* arr; // just to make it accessible so that we can tract the contents;
foo(int _n);
foo(int* _a, int len);
foo(const foo & rhs);
foo & operator=(const foo & rhs);
~foo();
};
void foo::init(int _n = 0){
n = _n;
arr = new int[n];
for(int i = 0; i != n; i++) arr[i] = 0;
}
foo::foo(int _n = 0){
init(_n);
}
foo::foo(int*_a, int len){
init(len);
for(int i = 0; i< len; i++) arr[i] = _a[i];
}
foo::foo(const foo &rhs){
operator = (rhs);
}
foo& foo::operator= (const foo &rhs){
if(debug) cout<<"\nassignment operator overloaded";
if (this != &rhs){
if(n != 0) {
n = rhs.n;
delete [] arr;
arr = new int[n];
for(int i = 0; i < n; i++) arr[i] = rhs.arr[i];
}
}
return *this;
}
foo::~foo(){
if (debug)cout << "\ndestructor called\n";
delete []arr;
}
int main(){
{ // a explicit block to see when the destructor is called;
foo* f = new foo[4];
int n = 4;
int a[] = {0,1,2,3};
for(int i = 0; i < n;i++) {
cout<<i;
f[i] = foo(a, i);
cout<<f[i].arr[i]<<"\n"; // result is some seemingly random number;
}
}
system("PAUSE");
}*
When you do this:
f[i] = foo(a, i);
a temporary foo object is created on the RHS of the assignment operator. It is then used to assign to the foo on the LHS of the operator. Then, it is destroyed, therefore its destructor is called.
The reason for the garbage values after the assignments is probably that n is 0 in all the foos in the array. Your assignment operator is broken. You may want to have a look at the copy and swap idiom.
A big no no! Delegating initialization of an uninitialized object to the assignment operator is a no good idea:
foo::foo(const foo &rhs){
operator = (rhs);
}
Better is:
foo::foo(const foo &rhs)
: n(rhs.n), arr(new int[n])
{
// copy rhs.arr to arr
}
// Note: Passing by value:
foo& operator = (foo rhs) {
std::swap(n, rhs.n);
std::swap(arr, rhs.arr);
return *this;
// Note: The swapped rhs will do the cleanup in the destructor
}
You will end up with less coding and exception safety
Another issue is:
cout << f[i].arr[i] << "\n"
You are printing an undefined 'end' value (arr[i] == arr[n])
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 a following class foo
class foo
{
int *arr; // arr holds numbers
int sz; // size of array
public:
// Suppose I have made default and 1 parameter c'tor
foo(const foo &f)
{
sz = f.sz;
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=f.arr[i];
}
};
int main()
{
foo x(5); //5 is size of array
const foo y = x; //doesn't work as I haven't initialized in member-initialization list, but how to write for loop in member initialization list ?
}
So How do I write for loop in member initialization list ?
You could just use a std::vector in this caseā¦ anyways.
Typically, I will create a private static method which will perform the allocation and copy. Then the initialization list may be used:
static int* CloneInts(const foo& f) {
int* ints = new ...
...copy them from #a f.arr...
return ints;
}
Then your init-list would look like:
foo(const foo& f) : arr(CloneInts(f)), sz(f.sz) {
Have you tried constructing it with the copy constructor directly?
const foo y(x);
You should clarify your problem, because the one in the question doesn't actually exist.
The const foo y = x; line will compile and work with that copy constructor. A const object under construction isn't "const' until the constructor has completed. So the constructor body is permitted to modify the object even if the object being constructed is const.
Also note that the loop in the example isn't even modifying anything that's ever const - since the array is allocated dynamically, those array elements are modifiable even if the object itself isn't. For example, the arr pointer isn't modifiable after the ctor has completed, but arr[0] still is.
Try out the following to see both points in action:
#include <stdio.h>
#include <algorithm>
class foo
{
int *arr; // arr holds numbers
int sz; // size of array
public:
foo() : arr(0), sz(0) { puts("default ctor");}
foo(int x) : arr(0), sz(x) {
puts( "int ctor");
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=0;
}
foo(const foo &f)
{
puts("copy ctor");
sz = f.sz;
arr = new int[sz];
for(int i=0;i<sz;i++)
arr[i]=f.arr[i];
}
~foo() {
delete [] arr;
}
foo& operator=(const foo& rhs) {
if (this != &rhs) {
foo tmp(rhs);
std::swap( arr, tmp.arr);
std::swap( sz, tmp.sz);
}
return *this;
}
void update() const {
for(int i = 0; i < sz; i++) {
arr[i] = arr[i] + 1;
}
}
void dump() const {
for(int i = 0; i < sz; i++) {
printf("%d ", arr[i]);
}
puts("");
}
};
int main()
{
foo x(5); //5 is size of array
const foo y = x;
y.dump();
y.update(); // can still modify the int array, even though `y` is const
y.dump();
}
I think you may be confusing constructing const objects with constructing objects that have const members since those members must be initialized in the initialization list.