In my main, I am calling a function (func1)in a loop. This function is a member of Class1. I am passing an object (object2) of a different class, Class2 to this function. On the first iteration of the loop, the variable var2 (member of Class2) is accessible from main, but on the second iteration, it is not. I get an "Access violation reading location" error. Here is what my code looks like:
main.cpp:
#include "Class1.h"
int main(){
Class2 object2;
object2.assign_var2();
Class1 object1;
for (int i = 0; i < 2; ++i){
std::cout << object2.var[0][0][0] << std::endl; // Works ONLY on first iteration
object1.func1(object2)
}
}
Class2.h:
class Class2{
... other variables and functions declared
public:
Class2::Class2();
Class2::~Class2();
double *** var2;
void assign_var2();
}
Class2.cpp:
Class2::Class2(){
var2 = new double**[200];
for (int i = 0; i < 200; ++i) {
var2[i] = new double*[200];
for (int j = 0; j < 200; ++j){
var2[i][j] = new double[2];
}
}
Class2::~Class2(){
for (int i = 0; i < 200; ++i){
for (int j = 0; j < 200; ++j){
delete [] var2[i][j];
}
delete [] var2[i];
}
delete [] var2;
}
void assign_var2(){
for (int i = 0; i<200; ++i){
for (int j = 0; j<200; ++j){
var2[i][j][0] = some_number1;
var2[i][j][1] = some_number2;
}
}
}
}
Class1.h:
#include "Class2.h"
class Class1{
... other variables, functions declared
public:
void func1(Class2)
}
Class1.cpp:
Class1::func1(Class2 object2){
int u = object2.var2[1][2][0];
int v = object2.var2[1][2][1];
}
Side note: If I try and print a different variable instead of var2, it seems to work on the second iteration, so I don't think it's a problem with the object itself.
Thanks in advance!!
The problem is that Class1::func1(Class2 object2) accepts the argument by value. This means that a copy of the Class2 object is being made, and then destructed when func1() returns.
In the Class2 class you do not define a copy constructor, so the compiler is creating one for you that simply copies the members by-value. Then when the copy's destructor runs, it deletes all of the allocations, leaving the original object with a pointer to an invalid object. This is why it fails on the second iteration.
Always follow the rule of three: if you need a custom destructor, copy constructor, or copy assignment operator, you need all three of them. A proper copy constructor will create new allocations for all of the arrays and copy the data to them. (If you are using C++11 then it's actually the rule of five: you probably also want to implement a move constructor and move assignment operator so that you can "steal" the var2 pointer in cases where you know that the object being assigned is an rvalue and therefore will be going away soon anyway.)
In your case, the fix is simple: accept the argument by value:
Class1::func1(Class2 const & object2)
I would strongly suggest using std::vector<std::vector<std::vector<double>>> for your var2 member instead, because then the compiler-generated destructor, copy-constructor, and copy-assignment operator will all do the right thing, and you won't need to implement any of them.
This works hand-in-hand with making func1() accept a reference: while the error is happening because there isn't a custom copy constructor, we really don't even want to make a copy here because we're not modifying the data. Copying the data only to destroy the copy is silly; let's just accept a reference to an existing object instead of requiring a superfluous copy.
Alternatively, you can just disable copying altogether:
class Class2 {
// ...
// For C++11: explicitly delete the copy-ctor and copy-assignment operator.
public:
Class2(Class2 const &) = delete;
Class2 & operator=(Class2 const &) = delete;
// For C++03: declare the copy-ctor and copy-assignment operator private and
// then do not implement them. (C++03 doesn't have the "= delete" syntax.)
private:
Class2(Class2 const &);
Class2 & operator=(Class2 const &);
If you disable copying then you would get a compile-time error on the call object1.func1(object2) because it depends on the existence of a copy-constructor for object2.
Related
So, for instance, I have the following code which I want a object's pointer
member to point to a memory which was pointed by another temporary object's
member.
struct A {
int * vals;
A(): vals(new int[10]) { }
~A(){ delete[] vals; }
};
int main() {
A a;
{
A temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = 100;
}
a.vals = temp.vals;
temp.vals = nullptr; // avoid double free
}
I set temp.vals to nullptr in case the destructor of temp will free that
memory. So far so good, I guess. However, if I change the vals to a dynamic
array, i.e. a pointer to pointers:
struct A {
int ** vals;
A(): vals(new int*[10]) {
for (int i = 0; i < 10; ++i) {
vals[i] = new int;
}
}
~A(){
for (int i = 0; i < 10; ++i) {
delete vals[i]; // illegal to dereference nullptr
}
delete [] vals;
}
};
int main() {
A a;
{
A temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = new int(1);
}
a.vals = temp.vals;
temp.vals = nullptr; // avoid double free
}
}
I have add a for loop in destructor to handle the nested allocated memory, and
to avoid the memory be freed by the destructor of temp, I set temp.vals to
nullptr, which, however will cause a segmentation fault since when destructor
of temp is called, it is illegal to dereference a nullptr.
So my question is, how to correct set the destructor to handle the dynamic array.
I'm not a native speaker, so please forgive my grammar mistakes.
The typical C++ solution looks a bit different:
class A {
private:
int* vals;
public:
A(): vals(new int[10]) { }
~A(){ delete[] vals; }
A (A const& src); // Copy constructor
A (A&& src) : vals (src.vals) { src.vals = nullptr; }
A& operator=(A const&); // Assignment
A& operator=(A &&);
};
You can now write a = std::move(temp). Outside the class, you don't need to know how the inside works.
For your 2D array, just define the same special member functions. This is usually called the "Rule of Five". If you need a destructor, you probably need the other 4 functions as well. The alternative is the "Rule of Zero". Use std::vector or another class that manages memory for you.
However, if I change the vals to a dynamic array, i.e. a pointer to pointers
In the first program, vals is a pointer. It points to a dynamic array of integers. In the second program, vals is also a pointer. It points to a dynamic array of pointers.
how to correct set the destructor to handle the dynamic array.
You set vals to null. If null is a valid state for vals, then it isn't correct to unconditionally indirect through it in the destructor. You can use a conditional statement to do so only when vals isn't null.
However, the program is hardly safe because vals is public, and thus it is easy to mistakenly write a program where it is assigned to point to memory that isn't owned by the object. In cases where destructor cleans up an owned resource, it is important to encapsulate the resource using private access to prevent accidental violation of class invariants that are necessary to correctly handle the resource.
Now that vals is no longer outside of member functions, you cannot transfer the ownership like you did in your example. The correct way to transfer the ownership is to use move assignment (or constructor). The implicitly generated move constructor cannot handle an owning bare pointer correctly. You must implement them, as well as the copy assignment and constructor.
Furthermore, you should use an owning bare pointer in the first place. You should use a smart pointer instead. If you simply replaced the bare pointers with unique pointer, then the implicitly generated move assignment and constructor would handle the resource correctly, and the copy assignment and constructor would be implicitly deleted.
Lastly, the standard library has a container for dynamic arrays. Its called std::vector. There's typically no need to attempt to re-implement it. So in conclusion, I recommend following:
std::vector<int> a;
{
std::vector<int> temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = 1;
}
a = std::move(temp);
}
There are still issues such as the temporary variable being entirely unnecessary, and the loop could be replaced with a standard algorithm, but I tried to keep it close to the original for the sake of comparison.
P.S. It's pretty much never useful to dynamically allocate individual integers.
For example, if I have this class:
class Counter {
public:
int* j = new int[5];
}
A pointer variable is initialized as a data member. If in my copy constructor, I have something like
int* j = new int[7] OR int* j = new int[5](),
therefore initializing the the data member as well, will it create a memory leak for the first one since it wasn't deleted beforehand? Or will the original data member not even initialize?
A default member initializer for a non-static data member will be used in constructors where the same data member is not present in the member initializers list
[...] will it create a memory leak ... ?
Yes.
A default member initializer (DMI) as used in your example:
class Counter {
public:
int* j = new int[5]; // default member initializer for data member 'j'
}
will only be used if, for a given constructor, the data member, here j, is not initialized in the member initializer list of that given constructor.
Thus, if you add a copy constructor to Counter with no member initializer list, the default member initializer for the data member j will be used, and thus you will have a memory leak.
We can study this behaviour by changing the DMI for the data member j into an immediately invoked lambda, to allow us to trace when the DMI is used or not, as well as a dummy copy ctor that simply copies the pointer of the copy-in argument through different means (this is just for this dummy example; see final paragraph regarding lifetime management as well as deep-copying vs shallow-copying):
#include <iostream>
struct Counter {
int* j = []() {
std::cout << "Calling DMI for j.\n";
auto p = new int[5];
return p; }();
// Uses the DMI for member 'j'.
Counter() {}
// Uses the DMI for member 'j'.
Counter(const Counter& c) { j = c.j; } // Memory leak.
};
int main() {
Counter c1; // Calling DMI for j.
Counter c2 = c1; // Calling DMI for j.
// Delete resource common for c1 and c2.
delete c2.p; // A rogue resource from c2 construction was leaked.
}
If your either perform the copying into the j data member in a member initializer list of the copy constructor:
#include <iostream>
class Counter {
public:
int* j = []() {
std::cout << "Calling DMI for j.\n";
auto p = new int[5];
return p; }();
// Uses the DMI for member 'j'.
Counter() {}
// Does not use the DMI for data member 'j'.
Counter(const Counter& c) : j(c.j) { }
};
int main() {
Counter c1; // Calling DMI for j.
Counter c2 = c1;
// Delete resource common for c1 and c2.
delete c2.p; // OK, no resources leaked.
}
or simply explicitly set the data member j to nullptr as part of a member initializer list in the copy ctor:
#include <iostream>
class Counter {
public:
int* j = []() {
std::cout << "Calling DMI for j.\n";
auto p = new int[5];
return p; }();
// Uses the DMI for member 'j'.
Counter() {}
// Does not use the DMI for data member 'j'.
Counter(const Counter& c) : j(nullptr) { j = c.j; }
};
int main() {
Counter c1; // Calling DMI for j.
Counter c2 = c1;
// Delete resource common for c1 and c2.
delete c2.p; // OK, no resources leaked.
}
you will be overriding the DMI for the data member j.
Note that you will need to take extra care when implementing manual memory management in terms of raw C-style pointers, which is a very common recipe for lifetime issues. If possible, instead rely on smart pointers such as std::unique_pointer or std::shared_pointer to avoid lifetime issues; this is, however, out of scope for this question. Note, also that in the contrived examples above, the copy constructor will be shallow-copying the int resource to which the j data member pointer of the copy-in argument points (and likely owns). For implementing a real case copy constructor, you likely want to deep-copy this resource.
The construction instantiation int* j = new int[5]; will trigger if there are no overwrites on it.
Let me give an example:
class Counter {
public:
Counter(int x) {}; // j will be initialized as int* j = new int[5];
Counter(double y) : j(nullptr) {}; // the line j = new int[5]; won't be invoked. instead j = nullptr;
int* j = new int[5];
}
By default copy constructor overwrites it by copying j.
So if you explicitly write copy constructor like
Counter(const Counter& c) : j(c.j) {};
it will work properly. But if you write it like
Counter(const Counter& c) {j=c.j;};
it will cause a memory leak.
I have a class A, which has as a member a pointer to a vector of pointers (current), the vector which contains a pair of an integer and an object of class B . I need to be able to create copies for objects of class A, and for that I use a Clone function (see code below). However, when I use this function, the pointers seem to be pointing to the same memory location, instead of different ones. I think the solution to this is to implement a copy constructor for my class in order to be able to properly copy my objects, but I am failing to do so.
Here is how my class looks like and the several tries I had for implementing the copy constructor:
class A {
public:
A();
A(const A &a);
~A();
A* Clone() {return new A(*this);}
std::vector<std::pair<unsigned int, B*>> *current;
};
EDIT: The constructor and destructor are implemented as follows:
A::A() {
current = new vector<std::pair<unsigned int, B*>>;
}
A::~A() {
std::vector<std::pair<unsigned int, B*>>::iterator cit = current->begin(), cend = current->end();
for (; cit != cend; ++cit) {
delete cit->second;
}
delete current;
}
Option #1:
A::A(const A &a){
*current = *a.current;
}
Option #2:
A::A(const A &a){
for(int i = 0; i < current->size(); i++) {
(*current)[i] = (*a.current)[i];
}
}
Option #3:
A::A(const A &a){
for(int i = 0; i < current->size(); i++) {
(*current)[i].first = (*a.current)[i].first;
(*current)[i].second = new B((*a.current)[i].second);
}
}
Options #1 and #2 give me segmentation fault, while for #3 I get the error: no match for operator *
Which is the correct way to implement the copy constructor and also should my Clone function be implemented differently?
Your constructor does not initialise the current member at all. In any of the options.
From there, accessing its value (i.e. the value of the pointer named current) gives undefined behaviour. And so does dereferencing it. The usages of *current or *a.current in all options (and variations therefore) therefore ALL give undefined behaviour.
If you insist that the member current must be a pointer, it must be initialised in ALL constructors. For example, the constructor A::A() (which you haven't shown) must look something like
A::A() : current(new std::vector<std::pair<unsigned int, B*>>(0))
{
// initialised current with no elements
// add pairs to the vector
current->push_back(std::make_pair(0U, new B));
current->push_back(std::make_pair(42U, new B));
}
and the copy constructor must start with something akin to
A::A(const A &a) : current (new std::vector<std::pair<unsigned int, B *>>(a.current->size())
{
for(int i = 0; i < current->size(); i++)
{
(*current)[i].first = (*(a.current))[i].first;
(*current)[i].second = new B((*(a.current))[i].second);
}
}
More generally, however, there is actually no reason for current to be a pointer created using operator new. In that case the constructors could be simplified to
A::A() : current(0)
{
// add pairs to the vector
current.push_back(std::make_pair(0U, new B));
current.push_back(std::make_pair(42U, new B));
}
and the copy constructor to
A::A(const A &a) : current (a.current.size())
{
for(int i = 0; i < current.size(); i++)
{
current[i].first = a.current[i].first;
current[i].second = new B(a.current[i].second);
}
}
You've also provided no compelling information to suggest that current needs to be vector<pair<unsigned, B *>> rather than vector<pair<unsigned, B>>. If the vector doesn't need to hold pointers (i.e. it holds objects directly) then, practically, you will not need to define the copy constructor at all - the compiler-generated default will suffice. And your code will not need to use operator new at all (except, possibly, in A::Clone()).
Note that, if you do actually need to hand-roll a copy constructor, you will probably need to also hand-roll an operator=() and a destructor. Look up "rule of three" (before C++11) or (C++11 and later) "rule of five" and "rule of zero" for more information.
I looked through different thread and I have a hard time understanding how to utilize copy constructor.
If I want to manipulate my class, but I need to have original values to do so, I have to create a copy.
class object {
public:
int member[5][5];
object(object&); <-- how do we create a copy here?
void manipulate() {
<<-- how do I call it here?
}
};
I've been trying different things such as object copy = object(object&) but it does not work.
object(object&); <-- how do we create a copy here?
One simple way is to omit the declaration, and let C++ compiler do it for you. Since your object does not allocate resources in its constructor's body, C++ can handle creating the copy constructor for you.
<<-- how do I call it here?
Like this:
object copy(*this);
... // Manipulate it here
object( const object &obj )
{
for ( size_t i = 0; i < 5; i++ )
{
for ( int j = 0; j < 5; j++ )
{
member[i][j] = rhs.member[i][j];
}
}
}
Or you can write simply
object( const object &obj ) = default;
because your copy constructor does not do something special.
As for its using then you may use it the following way
object one;
onject two( one );
or
object one;
onject two = one;
or even as
object one;
onject two { one };
or
object one;
onject two = { one };
Also take into account that if you explicitly defined the copy constructor then you should explicitly define the default constructor if you need to have it.
A copy constructor is usually created because you cannot use the one generated by the compiler. In such a case, you will usually copy each member one by one.
For example (written on the fly - not sure if it would even compile with errors/warnings)
class A
{
public:
A();
A(const A& src)
{
m_array = (char*)new char[src.m_arraySize];
memcpy(m_array, src.m_array, src.m_arraySize);
m_arraySize = src.m_arraySize;
}
private:
char* m_array;
int m_arraySize;
};
I have to create a function which overloads the = operator so that when you put object1 = object2; it'll copy over all the values inside object2 into object1.
My class looks like:
class foo {
private:
int max;
int *val;
size_t *listofVal;
}
And my overload function is declared as:
foo& foo::operator=(const foo& matrix);
foo::foo(std::istream& s); //constructor
how would I do this?
The best way to do this is by using Copy and Swap Idiom.
Also, note that if you feel the need of overloading the copy assignment operator then you also probably need to overload copy constructor as well as the destructor for your class.
Do have a look at Rule of Three.
Simply copying all the values is the default behaviour of the compiler supplied copy contructor. This is known as a "shallow-copy".
More elaborate behaviour is achieved by implementing your own constructor so that the objects (here values) pointed to by your reference are created anew in the copy.
foo::foo(std::istream& s) {
max = s.max;
val = new int;
*val = s->val;
listofVal = new size_t;
*listofVal = s->listofVal;
}
would be one way of achieving that which is known as a "deep copy".
But as one of your members is called listofVal I rather feel you are doing something other than storing a single value at the memory address it points, in which case you should be holing a counter to the number of elements contained therein, which I will henceforth assume to be the field you call max. To copy the whole list, your copy constructor would then need to be:
foo::foo(std::istream& s) {
max = s.max;
val = new int;
*val = s->val;
listofVal = new size_t[max];
for (int i = 0; i < max; ++i)
listofVal[i] = s->listofVal[i];
}
Ravi, yes, the copy constructor is a proof of construct and despite breaking the "Rule Of Three" can be implemented before the other two. Here is the assignment operator.
foo& foo::operator=(const foo& matrix) {
if (this != matrix) {
max = matrix.max;
val = new int;
*val = matrix->val;
listofVal = new size_t[max];
for (int i = 0; i < max; ++i)
listofVal[i] = matrix->listofVal[i];
}
}
would be suitabe for object1 = object2; assignment. I tend towards the copy constructor approach.
The methods need to be members to access the private data so your class should be like
class foo {
///...///As before
foo &operator=(const foo& matrix);
};
Of course it needs a destructor but as it was not explicitly requested I didn't want to answer what wasn't asked.
Following on from the link to the Copy and Swap idiom, when the LHS may already contain data, for robust assignment you might consider:
foo& foo::operator=(const foo& matrix) {
if (this != matrix) {
val = new int;
*val = matrix->val;
size_t* newArray = new size_t[max];
int newMax = matrix.max;
std::copy(matrix.listofVal, matrix.listofVal + max, newArray);
if (listofVal) delete listofVal;
listofVal = newArray;
max = newMax;
}
}
I would add that assigning local objects on the heap can cause memory leaks (if the method breaks before they are assigned to an object responsible for their deletion), but that is just a whole nother layer of parannoia when we have enough to do preserving class integrity.
Googling for "C++ Assignment Operator" gives you this useful site ;-)