So I'm unsure as to what the correct way is to do this. I have a class named someClass, with a private variable that is an array of integers. The size doesn't get defined until the constructor is called. Here's how I do it:
In someClass.h:
class someClass {
public:
someClass();
someClass(int size);
~someClass();
private:
int* array;
}
In someClass.cpp:
someClass::someClass() {
array = new int[9];
}
someClass::someClass(int range) {
array = new int[range];
}
someClass::~someClass() {
delete[] array;
}
Did I declare/define the array correctly? Would it have been much better to use a vector?
Is the destructor correct?
Yes, you're doing it correctly (partially), and yes, it would be better to use a std::vector (because of the "partially" part).
The "partially" is that now you will have to provide a copy constructor and copy assignment operator for your class (and for efficiency, you might want to have a move constructor and move assignment operator as well); if you don't, you'll get double deletion errors if you ever copy the class.
std::vector encapsulates all this, so this is why you should prefer it. Not to mention that it has nice features like iterators.
Your class would then look like this:
class someClass {
public:
someClass();
someClass(int size);
//no destructor necessary!
private:
std::vector<int> array;
}
someClass::someClass()
{} // nothing special needed
someClass::someClass(int range) : array(range)
{}
You should also add copy ctor and copy assignment operator. Remember the rule of three!
Related
I have a long class with a lot of data members. I want to write a copy constructor for it. But, if I write my own copy constructor, I lose access to the default copy constructor.
I just want to repair a few pointers in my own copy constructor. So I want to have a shallow copy of the object which can be done by the default copy constructor.
Is there a possibility to access the default copy constructor when I have my own copy constructor?
Wrap the things you don't want to change in a struct, and derive (privately) from it. In your copy constructor, simply invoke the copy constructor of your base class.
No you cannot have both default and your own copy c-tor.
But there are two workarounds with this problem:
1 Enclose your pointers in some class with defined copy semantics
Example:
class A {
public:
private:
int trivial1;
int trivial2;
...
SomePointer nontrivialMember;
};
class SomePointer {
public:
SomePointer(const SomePointer&); // here the non trivial part of A copy semantics
int* nonTrivialMember;
};
2 Enclose the trivial parameters in some trivial structure
Example:
class A {
public:
A(const A& o) : data(o.data) {
// non trivial part
}
private:
struct Data {
int trivial1;
int trivial2;
...
} data;
int* nontrivialMember;
};
I would always select the first solution.
[UPDATE]
There is also 3rd solution, very similar to my second, enclose your trivial part in privately inherited base class. I'd still prefer the 1st solution.
The simplest approach to this would be to wrap up the pointers into classes that will perform the 'repair' manually in their copy constructor, then you can happily use the default copy constructor.
No, there is no way to call the default copy constructor from an user defined copy constructor.
You can either use the default or your own, not both. If you want to choose different functionality for different objects you should just write a member function that handles that case.
void DeepCopy(MyClass* rhs);
For example.
You cannot access default copy ctor if you created your own - compiler just doesn't generate it. But ther is workaround - split you class into data structure and logic.
See example:
struct Data
{
int i;
std::string s;
Data(): i(), s() {}
};
class Code: private Data
{
public:
Code() {}
Code(const Code& rhs): Data(rhs) // Call default copy ctor
{
i = 42; // Your copy part
return *this;
}
};
My solution is a simple memcpy() instead of the impossible call to the implicit (compiler generated) copy constructor, as the example shown below:
Class Foo
{
public:
...
Foo (Foo & other) {
// copies trivial part (and non-trivial part with possible wrong values)
memcpy(this, &other, sizeof(Foo));
// your non-trivial part here, overwrites the wrong values (if any) above.
}
}
Yet the side-effect is that the memcpy() will also copy those non-trivial part, which is a waste. If the non-trivial part does not contain too much space, I will prefer my solution.
For example, a class like below wastes only 4 byte copy of the one pointer, assuming the size of a pointer is 4 bytes.
Class Bar
{
int x, y, z;
// memcpy() wastes these 4 bytes copy,
// since actual copy constructor wants a new string
string *s;
}
This worked for me... (C++11, don't know if it works on older std)
Not sure why it doesn't end up in an endless loop.
class Foo {
public:
Foo(const Foo &orig) {
*this = orig;
... exchange pointers, do own stuff
}
I am quite new to c++ and I have a question.
If I have a class containing a (pointer to a) vector:
class myClass {
public:
int* direction;
myClass(int d){direction=new int[d];}
}
When I create an object and delete it in the main:
int main(){
int d;
myClass* myvec;
myvec = new myClass(d);
delete myvec;
}
Also the destructor for myvec->direction has been coherently called and the memory freed? Or do I have to write an apposite method for that?
I hope the question is clear...
If you've allocated memory with new you need to delete it too, like this:
class myClass {
int* direction;
public:
myClass(int d) : direction(new int[d]) {}
~myClass() {
delete[] direction;
}
}
But you'd also need to write a copy constructor and copy assignment operator, and in C++11 and later also a move constructor and move assignment operator, for this to be working good. Otherwise, you'd risk the default versions of those copying the raw pointer when you use instances of this class.
Take a look at the rule of three/five/zero.
You'd be much better off using a std::vector<int> instead of a raw pointer.
I'm a beginner to c++ so there are a lot of things quite not clear in my mind.
I have this code I need to write and in a class I make a constructor.
However, I don't need any parameters because I read from a file-stream inside the constructor. So my questions are:
1.Can I make a constructor like this:
class myClass {
private:
string title;
string organizer;
public:
myClass() {
title = stringRead();
organizer = stringRead();
}
}
where stringRead() is a function I have written to read from my file??
2.How do I call it afterwards when I need it? I know that the default constructror is being called like that:
myClass A;
A = myClass();
Is it the same?
3.If I have a pointer, how do I call the constructor again? This doesn't seem like it should be right...
myClass *B;
B = myClass();
Thanks in advance! =D
1) This constructor will work but you should favor using an initialization list (assuming stringRead() isn't a member function of myClass
class myClass {
private:
string title;
string organizer;
public:
myClass()
: title(stringRead()),
organizer(stringRead())
{ }
};
2) myClass A; is what you should be doing. You could alternatively have auto A = myClass(); which, after optimizations, will be the same thing. Without optimizations a temporary will be constructed, and then A will be move constructed from it, so this won't work with unmovable objects (your object is movable)
3) If you want to use a raw pointer then you would use
myClass *ptr = new myClass;
// bunch of code
delete ptr;
However, you'd be better using a smart pointer to control its lifetime. This way you won't need to manually delete
std::unique_ptr<myClass> ptr(new myClass);
or make_unique in c++14
auto ptr = std::make_unique<myClass>();
And of course use a shared_ptr if you have shared ownership
I think it's OK to assign the value returned by a function to a member of a class.
You can initialize it as you suggested (with myClass A;)
When you use pointers, you need myClass *k=new myClass();. You should remember to delete the object you created with delete k;.
Your constructor is fine, so long as the functions used within it are globals or static functions of this or another class.
myClass A; will invoke the constructor you have written.
To use a pointer, you need B = new myClass(). That will also call the same constructor. Don't forget to delete B at some point else you'll leak memory.
Do bear in mind that if an exception is thrown in a constructor then the destructor is not called.
Yes, you can, but it might not be the best approach. Reading from input can fail, failure in a constructor is often a non-recoverable event you'll want to handle. A good approach is reading the values outside the costructor, handling errors and calling the constructor only when you have "everything ready". Like this:
class myClass {
private:
string _title;
string _organizer;
public:
myClass(const string &title, const string &organizer) {
_title = title;
_organizer = organizer;
}
or, by using a more idiomatic C++ initializer list:
class myClass {
private:
string _title;
string _organizer;
public:
myClass(const string &title, const string &organizer):
_title(title), _organizer(organizer) {}
}
and then, somewhere else:
string title = stringRead();
string organizer = stringRead();
myClass A(title, organizer);
No, in this snippet:
myClass A;
A = myClass();
two different things happen: at line 1 the default constructor is called; at line 2, a temporary object is constructed (again, by calling the default constructor) and then assigned to A using the (rval for C++11) copy operator. This expression:
myClass A;
calls the default constructor. If you have parameters:
myClass A(title, organizer);
Nope, this does not even work. A pointer is not an object, you have to allocate the object. At that point, you can get a pointer to it:
myClass A;
myClass *B = &A;
you could also resort to dynamic allocation:
myClass *B = new myClass;
in this case, either remember to call delete B somewhere else or wrap B in a smart pointer:
std::unique_ptr<myClass> B(new myClass());
Is this code valid in C++?
class MyClass
{
public:
Class2 array [100];
Myclass (const Myclass& other) : array (other.array) {}
};
If it isn't, what's the best way to achieve the same result?
In C++ arrays are not explicitly copyable (not copy-constructible, not assignable). Your code will not compile.
Yet in C++ arrays become indirectly copyable when wrapped into a class. This means that if you remove your constructor definition, then the implicit copy constructor generated by the compiler for your class MyClass will actually successfully copy the array by some "magical" means that are not available to you directly.
But if for some reason you have to define the copy constructor explicitly, then your options are restricted to leaving the array default-initialized and then explicitly copying the data in the body of the constructor through std::copy or something similar. Or you can simply re-wrap your array, which is actually what the already suggested std::array can do for you.
Regardless of whether or not this is valid, if all your copy constructor does is to copy the array, then I would rather avoid writing it and let the compiler generate one implicitly.
Also, I would recommend following chris's advice in C++11 and use std::array rather than C-style arrays:
#include <array>
class MyClass
{
public: // In case you really want this to be public
std::array<Class2, 100> arr;
};
By the way, this would also allow you to initialize you array in the copy constructor's initializer list (but again, do this only if needed):
class MyClass
{
public:
MyClass() { }
MyClass (const MyClass& other) : arr(other.arr) {}
// ^^^^^^^^^^^^^^
private:
std::array<Class2, 100> arr;
};
Here is a live example.
I am not able to understand this behavior. I have a class A,
class A
{
public:
int ch;
char *s;
A()
{}
A(char *st):ch(0)
{
s = new char[10];
strcpy(s,st);
}
A(const A& rhs):ch(rhs.ch)
{
s = new char[strlen(rhs.s)+1];
strcpy(s,rhs.s);
}
const A& operator=(const A& rhs)
{
char *temp = new char[strlen(rhs.s)+1];
strcpy(temp,rhs.s);
delete[] s;
s=temp;
ch = rhs.ch;
return *this;
}
~A()
{
delete []s;
}
};
Till this point everything goes as expected I am able to test my copy constructor and assignment operator and they are working properly.
Now I created a child class B and I am getting heap corruption error. I am not able to understand, is this the problem related somewhere with class A destructor. ?
Below is my class B,
class B:public A
{
public:
int a;
B():a(0){}
};
You default constructor for A does not initialise the member s (a pointer):
A()
{}
Hence when elements are constructed using this constructor, you get a crash when the destructor deletes the uninitialized element:
~A()
{
delete []s;
}
Class B uses the default constructor for A, and therefore triggers this problem. Avoid it by properly initializing all members in the default constructor:
A() : ch(), s(0)
{ }
To solve your problem all you need to do is to replace:
char *s;
with
std::string s;
Just get rid of the manual memory management through char *, this is precisely the reason C++ provides you with std::string.
What might be the problem?
Your default constructor which does not take any arguments does no dynamic allocation.
If you created the class object through this constructor, Your destructor ends up deleteing a pointer which was not allocated with new and thus resulting in Undefined Behavior.
In the destructor, you delete[] s;, but in the default constructor, you haven't new[]ed s. In fact, you haven't even initialized s.
The default constructor of the base class is called when you instantiate the derived class because you have not initialized the base otherwise (: A(...)). Therefore, you have no idea what you're deleting, or even what you're going to have for breakfast tomorrow, because it's undefined behaviour.
To keep it consistent, new[] s in the default constructor. To save headache, I would suggest something like std::string instead of character pointers.