C++ How to store object in arrays without them deleted - c++

I want to seek help on this issue I encountered when learning C++. I tried to store objects into an array directly, but realize the objects gets deconstructed right away. I could not figure out why exactly is this so.
#include <iostream>
class Thing{
public:
~Thing(){
std::cout<<"Thing destructing";
}
};
int main(){
Thing arr[1];
arr[0] = Thing();
int x;
std::cin>>x;
};

In this statement
arr[0] = Thing();
there is used the default copy assignment operator that assigns the temporary object created by this expression Thing() to the element of the array. After the assignment the temporary object is destroyed.
To make it more clear run this demonstration program.
#include <iostream>
class Thing
{
public:
~Thing()
{
std::cout<<"Thing " << i << " destructing\n";
}
Thing & operator =( const Thing & )
{
std::cout << "Thing " << i << " assigning\n";
return *this;
}
Thing() : i( ++n )
{
std::cout << "Thing " << i << " constructing\n";
}
private:
size_t i;
static size_t n;
};
size_t Thing::n = 0;
int main()
{
{
Thing arr[1];
arr[0] = Thing();
}
std::cin.get();
return 0;
}
Its output is
Thing 1 constructing
Thing 2 constructing
Thing 1 assigning
Thing 2 destructing
Thing 1 destructing

Assuming you don't know already.
Smart-Pointer
#include <memory>
// ...
int main() {
std::shared_ptr<Thing> arr[1];
arr[0] = std::shared_ptr<Thing>(new Thing());
// ...
// <-- Is automatically deleted around here.
}
Pointer
Not-Recommended;
Using pointer would look like:
int main() {
Thing *arr[1] = {};
arr[0] = new Thing();
int x;
std::cin >> x;
// WARNING: remember to manually delete.
delete arr[0];
} // <-- BTW, you don't need semi-colon.

Related

Only one variable is working at a time, and it is dependent on which order I declare them in

I really didn't know what to put as the title for this so ignore that. I also don't know how to describe the question so here is my issue.
#include <iostream>
#include <vector>
class ClassB {
public:
//LOOK AT THIS PART
int value;
char letter;
ClassB(char t, int v) {
letter = t;
value = v;
}
};
class ClassA {
private:
ClassB* ptr;
public:
ClassA(ClassB n) {
ptr = &n;
}
ClassB* getPtr(){
return ptr;
}
};
int main() {
std::vector<ClassA> objects;
for(int i=0;i<4;i++) {
objects.push_back(ClassA(ClassB('a',i)));
}
std::cout << "Value: " << objects[1].getPtr()->value << std::endl;
std::cout << "Letter: " << objects[1].getPtr()->letter;
return 0;
}
In this code, the output I should receive is
Value: 1
Letter: a
However I am receiving this
Value: 1
Letter
Also, if I were to declare letter before value (look at the comment in code), then the output would say
Value: 0
Letter: ☺
I'm not sure why the order I declare them in would affect anything, or why I'm getting a smiley face instead of a. Any help is appreciated, thank you!
The problem lies here:
ClassA(ClassB n) {
ptr = &n;
}
ClassB is a temporary variable that gets destructed at the end of the function. The pointer becomes invalid and the program goes nuts.
A simple and safe way to go about this, is to use an std::unique_ptr and pass parameters. unique_ptr will automatically delete ClassB when ClassA is deleted:
private:
std::unique_ptr<ClassB> ptr;
public:
ClassA(char t, int v) {
ptr = std::make_unique<ClassB>(t, v);
}
There's also just keeping a value instead of a pointer.

I assigned a variable to the value of what is stored at a pointer's address, so why doesn't it change when the initial value does?

Basically, I just want to know why 'C' doesn't change when 'A' does. I'm guessing that it's because of the hierarchy, but I wanted to confirm and get an explanation as to why...
#include <iostream>
using namespace std;
class IntCell
{
public:
explicit IntCell( int initialValue = 0 )
{ storedValue = new int{ initialValue }; }
int read() const
{ return *storedValue; }
void write( int x )
{ *storedValue = x; }
private:
int *storedValue;
};
int main() {
IntCell a{ 2 };
IntCell* b = &a;
IntCell c;
int x = 10000;
int* y = &x;
cout << *y << endl;
c = *b;
a.write(4);
cout << a.read() << endl << c.read();
return 0;
}
I test your code and when you change "a", "c" change too.
Also You need to implement a copy constructor and assignment operator.
IntCell c; // you create a new instance with new memory address.
c = *b; // now this instance point to same memory as "a".
a.write(4); // so when you change "a", "c" change too.
In your case, the destructor is missing.
~IntCell(){
cout<<"deleting...\n";
delete storedValue;
}
You are using the implicitly-defined copy assignment. That is why c = *b; works. After the copy assignment, IntCell c and IntCell a both have the member which points to the same location. If a.write(4), c.read() will get the same value 4.

std::vector with elements allocated on the heap - do I need rule of 5?

If I have a class with members like this:
class MyClass {
public:
void set_my_vector() {
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, i*2));
}
}
private:
struct MyStruct {
int num_a;
int num_b;
MyStruct(int i, int j) : num_a(i), num_b(j) {}
};
std::vector<MyStruct*> my_vector;
};
Do I need to write the rule-of-five functions, or will std::vector take care of deep copying and deleting the elements allocated on the heap?
EDIT:
The following code uses default copy constructor, so I assume that after I copy my_class1 object into my_class2 object, the elements of my_class1.my_vector and my_class2.my_vector will be the same, because the MyStruct pointers were copied, but not the data itself. However, the output shows that they are not the same. You can run the code here: https://onlinegdb.com/S1pK9YE4v
#include <iostream>
#include <vector>
class MyClass {
public:
void fill_my_vector(int i, int j) {
my_vector.clear();
for (int ind = 0; ind < 3; ++ind) {
my_vector.push_back(new MyStruct(i, j));
}
}
void print () {
for (int ind = 0; ind < 3; ++ind) {
std::cout << my_vector[ind]->int1 << ", " << my_vector[ind]->int2 << std::endl;
}
std::cout << std::endl;
}
private:
struct MyStruct {
MyStruct (int i, int j) :
int1(i), int2(j)
{}
int int1;
int int2;
};
std::vector<MyStruct*> my_vector;
};
int main()
{
MyClass my_class1;
my_class1.fill_my_vector(42, 43);
std::cout << "my_class1: " << std::endl;
my_class1.print();
MyClass my_class2 = my_class1;
my_class2.fill_my_vector(12, 13);
std::cout << "my_class2: " << std::endl;
my_class2.print();
std::cout << "my_class1: " << std::endl;
my_class1.print();
}
EDIT2: I know about smart pointers. I am specifically interested what happens if I use raw pointers.
You need to implement the copy constructor, copy assignment and destructor.
Additionally, consider changing your vector declaration from
std::vector<MyStruct*> my_vector;
to
std::vector<std::unique_ptr<MyStruct>> my_vector;
so that it actually owns the heap allocated objects properly. Doing this change will help you not write a destructor.
No, std::vector doesn't take care of deep copying of your objects stored by pointer. You have few possibilities to solve this:
Store MyStruct by value.
Store std::unique_ptr<MyStruct>.
Store std::shared_ptr<MyStruct>.
Note that because MyStruct contains only fields of the primitive types, neither of copy constructor, assignment operator and destructor are needed, otherwise you'd have to implement them, default implementation which compiler will generate automatically will be good enough.

How do you copy a object?

I am trying to make a deep copy of the object but for some reason I keep getting an error thrown at me.
Invalid address specified to RtlValidateHeap( 000002081EF60000, 000002081EF755C0 )
What does this mean? I have commented out the last two lines as this is not what causes the error but is what I would like to achieve.
#include "pch.h"
#include <iostream>
class Constant
{
public:
int Value;
Constant(int value) {
Value = value;
}
void set_value(int new_value) {
Value = new_value;
}
int get_value() {
return Value;
}
};
int main() {
std::shared_ptr<Constant> foo = std::make_shared<Constant>(1);
std::shared_ptr<Constant> bar(foo.get());
//bar->set_value(4);
//std::cout << (foo->get_value()) << " should be differnt than " << (bar->get_value());
return 0;
}
I expect the output "1 should be different from 4".
You are getting heap corruption due to a double-free problem. Your second shared_ptr is constructed with a raw pointer, which is already managed by the first shared_ptr. So both try to manage the same object, which leads to a double-free at the end of the scope.
To make a copy of an object in C++, just use copy construction:
#include "pch.h"
#include <iostream>
class Constant
{
public:
int Value;
Constant(int value) {
Value = value;
}
void set_value(int new_value) {
Value = new_value;
}
int get_value() {
return Value;
}
};
int main() {
Constant foo(1);
Constant bar(foo); // copy-construction
bar.set_value(4);
std::cout << (foo.get_value()) << " should be differnt than " << (bar.get_value());
return 0;
}
Note: in this example it is sufficient to rely on the default compiler-generated copy constructor.
Phil1970 got it right in the comments.
#include "pch.h"
#include <iostream>
class Constant
{
public:
int Value;
Constant(int value) {
Value = value;
}
void set_value(int new_value) {
Value = new_value;
}
int get_value() {
return Value;
}
};
int main() {
std::shared_ptr<Constant> foo = std::make_shared<Constant>(1);
std::shared_ptr<Constant> bar = std::make_shared<Constant>(*foo);
bar->set_value(4);
std::cout << (foo->get_value()) << " should be differnt than " << (bar->get_value());
return 0;
}
His solution allows you to use shared pointers and still obtain the desired result. Thanks Phil!
When you call this function:
std::shared_ptr<Constant> bar(foo.get());
You are directly taking the data pointer of the ptr internal and adding an additional controller(bar) to it. So don't pass the data ptr instead of the share ptr itself to the constructor.It should be like:
std::shared_ptr<Constant> bar(foo);

C++ confusion with new and scope

I am trying to learn C++ and from what I've read in books and on SO:
If I use auto x = new Object(); x is a pointer to address of Object and this is in dynamic memory and exists until I delete it.
However if I use Object x; or auto x = Object() it only lasts until it goes out of scope.
In an example they have shown this:
void foo()
{
Point p = Point(0,0);
} // p is now destroyed.
What I don't understand is what happens when I return a object when I don't use new? Will it be a copy of the object?
Here is an example of what I am not sure about:
class Object
{
public:
int X;
static Object Foo(int y)
{
Object result;
result.X = y;
return result;
}
};
class TestContainer
{
public:
void Run()
{
for(auto i = 0; i < 10; i++)
{
_objects.at(i) = Object::Foo(i + (rand() % 10 + 1));
}
}
private:
std::vector<Object> _objects;
};
void main()
{
TestContainer tc;
while(true)
{
tc.Run();
}
}
Note I haven't tested this code but I think it illiterates my confusion. In my main function I instantiate TestContainer and endless call it's Run method. This in turn loops calling a static Foo method on Object that returns a copy of a new Object, which is stored in a vector.
My question is, what happens with all the Object's? If I replace element 2 in the objects vector with a new Object, is the old value now "out of scope" and is deleted?
Will it be a copy of the object?
Yes.
Or a move could be used instead, or the entire thing could be optimised away to produce only one actual object in your final, compiled program.
But, basically, yes.
If I replace element 2 in the objects vector with a new Object, is the old value now "out of scope" and is deleted?
Yes.
As an aside, you're using at on elements that don't exist; to add elements, use insert or push_back.
A simple class like this behaves much like a POD variable. o1=o2 copies the fields, element-wise. So the target Object of an assignment does not get deleted but overwritten.
Objects which go out of scope "go away" (because the stack is unwound) like e.g. an int.
Here is a run-able example that I believe illustrates this behavior:
#include <iostream>
using namespace std;
class Foo {
private:
int id;
public:
Foo(int x)
: id(x)
{
cout << this->id << " is created" << endl;
}
Foo(const Foo& rhs)
: id(rhs.id)
{
cout << "copied " << this->id << endl;
}
Foo& operator=(Foo rhs){
this->id=rhs.id;
cout << "assigned " << this->id << endl;
return *this;
}
~Foo(){
cout << this->id << " is destroyed" << endl;
}
int getID(){
return this->id;
}
};
Foo bar(){
Foo f1 = Foo(1);
cout << f1.getID() << " from bar" << endl;
return f1;
}
int main(){
Foo f2 = bar();
cout << f2.getID() << " from main" << endl;
return 0;
}
This produces this output:
1 is created
1 from bar
1 from main
1 is destroyed
From this, I'm not seeing a copy or an assignment. I suspect what is happening is that both f1 and f2 are referencing the same instance of the object in memory. The object is not being de-allocated when the f1 reference goes out of scope because the object has another reference assigned to it.