C++ vector of objects and excessive calls to destructor? - c++

What I'm wondering about is whether the code calls the destructor one too many times and if its correct to code in this manner. It seems like the object created goes out of scope before getting loaded into the vector but the object doesn't die, instead it stays in the vector and ends up destructing again when the program is done. Heres the output:
object::constructor:
before push_back
object::destructor:
object::constructor:
before push_back
object::destructor:
object::destructor:
object::call(): begin
0
object::call(): end
object::call(): begin
1
object::call(): end
object::destructor:
object::destructor:
Process returned 0 (0x0) execution time : 0.313 s
Press any key to continue.
This is the main.cpp
#include <vector>
#include <iostream>
#include "object.h"
int main()
{
int max = 2;
std::vector <object> OBJECTS;
for(int index = 0; index < max; index++)
{
object OBJECT(index);
std::cout<<"before push_back"<<std::endl;
OBJECTS.push_back(OBJECT);
}
for(int index = 0; index < max; index++)
OBJECTS[index].call();
return 0;
}
and this is the object.h
#ifndef OBJECT_H
#define OBJECT_H
#include <iostream>
class object
{
private:
int value;
public:
object(){}
object(int value)
{
std::cout<<"object::constructor: "<<std::endl;
this->value = value;
}
~object()
{
std::cout<<"object::destructor: "<<std::endl;
}
void call()
{
std::cout<<"object::call(): begin"<<std::endl;
std::cout<<value<<std::endl;
std::cout<<"object::call(): end"<<std::endl;
}
};
#endif
This is the code from the answer Chowlett below, just in case the site goes under.
#include <iostream>
#include <vector>
class object
{
private:
int value;
public:
object(){}
object(int value)
{
std::cout<<"object::constructor: "<< value << std::endl;
this->value = value;
}
object( const object& o )
{
std::cout<<"object::copy-constructor: " << o.value << std::endl;
this->value = o.value + 10;
}
~object()
{
std::cout<<"object::destructor: "<< value << std::endl;
}
void call()
{
std::cout<<"object::call(): begin"<<std::endl;
std::cout<<value<<std::endl;
std::cout<<"object::call(): end"<<std::endl;
}
};
int main()
{
int max = 3;
std::vector <object> OBJECTS;
for(int index = 0; index < max; index++)
{
object OBJECT(index);
std::cout<<"before push_back: capacity="<< OBJECTS.capacity() << std::endl;
OBJECTS.push_back(OBJECT);
std::cout<<"after push_back: capacity="<< OBJECTS.capacity() << std::endl;
}
for(int index = 0; index < max; index++)
OBJECTS[index].call();
return 0;
}

The compiler generated a copy-ctor for you. Add one with some debug output and you can understand what your code is doing:
object( const object& o )
{
std::cout<<"object::copy-constructor: "<<std::endl;
this->value = o.value;
}

What's happening is that the vector is reallocating to make space.
OBJECTS starts off with capacity equal to zero. The loop constructs OBJECT = object(0), then copy-constructs a copy of that object to pass to push_back. push _back notes there's not enough room (1 > 0!), so it reallocates vector to have a capacity of 1 and puts the copy in. Then it destructs OBJECT.
Next time through the loop, OBJECT = object(1) is constructed, then copy-constructed for push_back. There's not enough room again, so OBJECTS is reallocated to have greater capacity - and the object(0) already in it is copy-constructed into the reallocated space, and the original destructed. Then the copied object is put in, and the OBJECT is destructed again.
This variation on your code should make it clear what's going on. I've made the code write the vector capacity before and after each push_back; and I've added a logging copy-constructer. I've also made the copy-constructer add 10 to value each time it's called, so you can see how each individual object is copied around.

Related

C++: Setters and Getters for Arrays

I am struggling to find the correct format for initializing a (private) array within a class and getting/setting the values from outside the class.
My code is semi-functional, but feels awkward in incorrectly formatted.
It is returning only the first element of the array, I want it to return all the contents. Read code comments for additional details.
Note: This is (a very small part of) a project I am working on for school -- an array must be used, not a vector or list.
student.h
class Student {
public:
// Upon researching my issue, I read suggestions on passing pointers for arrays:
void SetDaysToCompleteCourse(int* daysToCompleteCourse[3]);
int* GetDaysToCompleteCourse(); // Ditto # above comment.
private:
int daysToCompleteCourse[3];
student.cpp
#include "student.h"
void Student::SetDaysToCompleteCourse(int* daysToCompleteCourse) {
// this->daysToCompleteCourse = daysToCompleteCourse; returns error (expression must be a modifiable lvalue)
// Feels wrong, probably is wrong:
this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
this->daysToCompleteCourse[1] = daysToCompleteCourse[1];
this->daysToCompleteCourse[2] = daysToCompleteCourse[2];
}
int* Student::GetDaysToCompleteCourse() {
return daysToCompleteCourse;
}
ConsoleApplication1.cpp
#include "pch.h"
#include <iostream>
#include "student.h"
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
int* ptr = daysToCompleteCourse;
student.SetDaysToCompleteCourse(ptr);
std::cout << *student.GetDaysToCompleteCourse(); // returns first element of the array (1).
}
I gave this my best shot, but I think I need a nudge in the right direction.
Any tips here would be greatly appreciated.
I would say:
// student.h
class Student
{
public:
// If you can, don't use numbers:
// you have a 3 on the variable,
// a 3 on the function, etc.
// Use a #define on C or a static const on C++
static const int SIZE= 3;
// You can also use it outside the class as Student::SIZE
public:
void SetDaysToCompleteCourse(int* daysToCompleteCourse);
// The consts are for "correctness"
// const int* means "don't modify this data" (you have a setter for that)
// the second const means: this function doesn't modify the student
// whithout the const, student.GetDaysToCompleteCourse()[100]= 1 is
// "legal" C++ to the eyes of the compiler
const int* GetDaysToCompleteCourse() const; // Ditto # above comment.
Student()
{
// Always initialize variables
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= 0;
}
}
private:
int daysToCompleteCourse[SIZE];
// On GCC, you can do
//int daysToCompleteCourse[SIZE]{};
// Which will allow you not to specify it on the constructor
};
// student.cpp
void Student::SetDaysToCompleteCourse(int* newDaysToCompleteCourse)
{
// It's not wrong, just that
// this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
// use another name like newDaysToCompleteCourse and then you can suppress this->
// And use a for loop
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= newDaysToCompleteCourse[i];
}
}
const int* Student::GetDaysToCompleteCourse() const
{
return daysToCompleteCourse;
}
// main.cpp
#include <iostream>
std::ostream& operator<<(std::ostream& stream, const Student& student)
{
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
stream << toShow[i] << ' ';
}
return stream;
}
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
// You don't need this
//int* ptr = daysToCompleteCourse;
//student.SetDaysToCompleteCourse(ptr);
//You can just do:
student.SetDaysToCompleteCourse(daysToCompleteCourse);
// On C++ int* is "a pointer to an int"
// It doesn't specify how many of them
// Arrays are represented just by the pointer to the first element
// It's the FASTEST and CHEAPEST way... but you need the SIZE
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
std::cout << toShow[i] << ' ';
// Also works:
//std::cout << student.GetDaysToCompleteCourse()[i] << ' ';
}
std::cout << std::endl;
// Or you can do: (because we defined operator<< for a ostream and a Student)
std::cout << student << std::endl;
}
You can check out it live here: https://ideone.com/DeJ2Nt

Why is the static array member variable showing nothing after calling the instance of the object?

Currently working on Object Oriented Programming in c++ and having problems with an instance showing nothing changed from a method I've created.
The whole code is based off of this object I've created from a header file.
#ifndef DEQUE_H_
#define DEQUE_H_
#include <iostream>
const int CAPACITY = 5;
const int DEFAULT = -1;
class Deque
{
public:
Deque();
int get_size() const;
bool is_empty() const;
bool is_full() const;
int operator[](int i) const;
static Deque insert_tail(int);
private:
int size_;
static int array_[CAPACITY];
};
std::ostream & operator<<(std::ostream &, const Deque &);
#endif
One of the problems I'm having is the insert_tail method that doesn't show any changes to my static array.
In the cpp file itself.. these are the function declarations.
#
include <iostream>
#include "Deque.h"
Deque::Deque()
:size_(0)
{
}
int Deque::array_[5] = {};
int Deque::get_size() const
{
return size_;
}
bool Deque::is_full() const
{
if (size_ == 5) return 1;
else return 0;
}
bool Deque::is_empty() const
{
if (size_!= 5) return 1;
else return 0;
}
int Deque::operator[](int i) const
{
int something = array_[i];
return something;
}
Deque Deque::insert_tail(int x)
{
Deque d;
d.size_ += 1;
int size = d.size_;
d.array_[size - 1] = x;
return d;
}
std::ostream & operator<<(std::ostream & cout, const Deque & dq)
{
cout << dq.get_size() << " [ ";
for (int i = 0; i < dq.get_size(); ++i)
{
cout << dq[i] << " ";
}
cout << "]";
return cout;
}
The operator works just fine. The bools work just fine and the remove_head and remove_tail thing I'll do once I figure out insert tail. Right now, it's not making any chances to the very object I've created inside the main.
#include <iostream>
#include "Deque.h"
void print(const Deque & deque)
{
static int i = 1;
std::cout << i << ". " << deque << ", empty: " << deque.is_empty()
<< ", full: " << deque.is_full();
i++;
}
void test_insert_tail(Deque & deque, int x)
{
deque.insert_tail(x);
print(deque); std::cout << "\n";
}
int main()
{
Deque deque;
print(deque);
std::cout << "\n";
test_insert_tail(deque, 2);
return 0;
}
The output should look like this,
1. 1 [ 2 ], empty: 0, full: 0
but looks like this
1. 0 [], empty: 1, full: 0
What's going on inside my static method for handling all the private attributes that I'm missing on? What did I do wrong exactly?
The problem with your code is the misuse of the static word. In fact, static means that is not associated with an instance of the object: this means that the content of the static member (the array_ variable in this case) is shared between every instance you will create.
That's the same for the insert_tail method, that can be used even if you don't create an instance. Now, let's try to understand what you've written in this method:
Deque d;
d.size_ += 1;
int size = d.size_;
d.array_[size - 1] = x;
return d;
In the first line, you created a new Deque object. That's the first mistake, cause you're not modifying the actual Deque. Then you add the operations, and in the end, you return the created Deque. However, this object is not saved anywhere, because when you call deque.insert_tail() you aren't assigning the returned value anywhere.
Let's try and get this a little bit more concrete.
Since what you're doing is creating a data structure, you won't need any static member. This because everything needs to be saved inside the data structure.
Then, inside the insert_tail you'll need to remove the object you created inside. It'll look something like this:
size_ += 1;
int size = size_;
array_[size - 1] = x;
With those two modifications the code will probably work as expected, however, I suggest you focus on improving the appearance of your code. Using the underscore character at the end of the variable name is a little bit confusing. In C the only scenario you can use it inside the name int foo_bar for normal variables, and at the beginning int _foo for reserved variables.

C++, Weird behavior of cout when trying to print integers

Im trying to write a class that stores an id and a value in an container class.
Im using an nested class as my data structure.
When im compiling the code sometimes it prints perfectly, sometimes it prints nothing and sometimes it prints half of the data then stops.
When i debug the code the same weird behavior occours, when it fails during debug it throws an error "Map.exe has triggered a breakpoint.", the Error occours in the print method when im using cout.
cmap.h
#pragma once
class CMap
{
public:
CMap();
~CMap();
CMap& Add(int id, int value);
void print() const;
private:
class container
{
public:
~container();
int container_id = 0;
int container_value = 0;
};
container* p_komp_;
int dim_ = -1;
void resize();
};
cmap.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
CMap::CMap()
{
p_komp_ = new container[0];
}
CMap::~CMap()
{
p_komp_ = nullptr;
cout << "destroy cmap";
}
CMap& CMap::Add(int id, int value)
{
resize();
p_komp_[dim_].container_id = id;
p_komp_[dim_].container_value = value;
return *this;
}
void CMap::resize()
{
container* temp_array = new container[++dim_];
if (dim_ == 0)
{
temp_array[0].container_id = p_komp_[0].container_id;
temp_array[0].container_value = p_komp_[0].container_value;
}
for (unsigned i = 0; i < dim_; i++)
{
temp_array[i].container_id = p_komp_[i].container_id;
temp_array[i].container_value = p_komp_[i].container_value;
}
p_komp_ = temp_array;
}
void CMap::print() const
{
for (unsigned i = 0; i <= dim_; i++)
{
cout << p_komp_[i].container_id;
cout << p_komp_[i].container_value;
}
}
CMap::container::~container()
{
cout << "destruct container";
}
Map.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
void main(void)
{
CMap m2;
m2.Add(1, 7);
m2.Add(3, 5);
m2.print();
}
These two things are a possible reason for your problem:
int dim_ = -1;
and
container* temp_array = new container[++dim_];
When you allocate, you increase dim_ from -1 to 0. That is you create a zero-sized "array", where every indexing into it will be out of bounds and lead to undefined behavior.
You also have memory leaks since you never delete[] what you new[]. I didn't look for more problems, but there probably a more.
And an "array" (created at compile-time or through new[]) will have indexes from 0 to size - 1 (inclusive). You seem to think that the "size" you provide is the top index. It's not, it's the number of elements.
It seems to me that you might need to take a few steps back, get a couple of good books to read, and almost start over.

Memory management basics?

With this code:
#include <iostream>
#include <vector>
#include <stdio.h>
struct x
{
int a;
const char* t;
};
int main()
{
std::vector<x> instances;
while(true)
{
printf("wait for key1\n");
getchar();
getchar();
{
for(int i = 0; i < 100000; i++)
{
x n;
n.a = i;
n.t = "x instance";
instances.push_back(n);
}
//x instance deleted right?
}
{
x x1, x2, x3;
x1 = instances[0];
x2 = instances[1];
x3 = instances[2];
std::cout << x1.t << std::endl;
std::cout << x2.t << std::endl;
std::cout << x3.t << std::endl;
instances.clear();
}
printf("wait for key2\n");
getchar();
getchar();
}
return 0;
}
I'm getting this output:
wait for key2
wait for key1
x instance
x instance
x instance
That's cute but I think I should get a output like this:
wait for key2
wait for key1
>>£#$###£#$½£#$½
>>£#$###£#$½£#$½
>>£#$###£#$½£#$½
Because x struct instances must be deleted. Am I wrong? And the true implemention should be like this:
#include <iostream>
#include <vector>
#include <stdio.h>
struct x
{
int a;
const char* t;
};
int main()
{
std::vector<x*> instances;
while(true)
{
printf("wait for key1\n");
getchar();
getchar();
{
for(int i = 0; i < 100000; i++)
{
x* n = new x();
n->a = i;
n->t = "x instance";
instances.push_back(n);
}
}
{
x* x1 = 0;
x* x2 = 0;
x* x3 = 0;
x1 = instances[0];
x2 = instances[1];
x3 = instances[2];
std::cout << x1->t << std::endl;
std::cout << x2->t << std::endl;
std::cout << x3->t << std::endl;
instances.clear(); /* delete x instances one-by-one like 'delete instances[i];' */
}
printf("wait for key2\n");
getchar();
getchar();
}
return 0;
}
I'm not clear about memory management. Why I can still get (non-new'd) 'x instances' after cleanup? Examples?
I've looked in link>> and I think x instances in the for loop must be deleted?
Update
Here is my example implementation for other people (beginners like me).
I'll use a sync'd queue for socket io packets and
I don't care about thread.join() just because my threads
are only workers, not managers! (what a real-life simulation!)
#include <iostream>
#include <thread>
#include <chrono>
bool b1 = true;
bool b2 = true;
//Of course you can create only 1 boolean for all threads (isAlive should be a good name for it)
//but this way provides more detailed thread aliveness control.
void process(bool* ref, int id)
{
bool my = *ref;
while (my)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "thread#" << id << std::endl;
my = *ref;
}
std::cout << "thread#" << id << " end." << std::endl;
}
int main()
{
std::thread(process, &b1, 0).detach();
std::thread(process, &b2, 1).detach();
std::cin.get();
b1 = false;
std::cin.get();
b2 = false;
//MS-DOS :(
std::cin.get();
return 0;
}
Posibble output:
thread#thread#10
thread#0
thread#1
thread#1
thread#0
//Hit the enter!
thread#1
thread#0
thread#0 end.
thread#1
thread#1
//Hit the enter!
thread#1
thread#1 end.
//Hit the enter!
When you add an element to vector with push_back, the element is copied into the vector. This means that the vector has its own copy of your element, and even if the element is deleted (either by you or by the end of the scope), the vector still contains the element.
When the vector is deleted, the vector takes care of deleting its elements one by one, all by itself, so you don't have to.
You can find more information about push_back here:
Adds a new element at the end of the vector, after its current last element. The content of val is copied (or moved) to the new element.
Your "improved" version, where you dynamically allocate the variables, is a misuse of pointers. If all you're doing is inserting the elements into the vector then there's no need to dynamically allocate them, because the vector won't even contain the dynamically allocated values - only copies of them.
You are putting a copy into the vector.
for(int i = 0; i < 100000; i++)
{
x n;
n.a = i;
n.t = "x instance";
instances.push_back(n); // <--- Copy of n is created and added to instances
}
When you do push_back, you insert the copy of your instance into the vector. So it does not matter that the original instance has been deleted. The strings are going to be lost, probably, because they were allocated locally and the original string was destroyed.
Regarding the strings not being deleted, it might be due to the fact that you assign a static string to the pointer. Try the same with the string which you create dynamically.
Nop, it shouldn't be deleted.
When you call push_back() on a vector, you are creating a copy of x inside the vector.
std::vector::clear() does not delete items, instead it calls any appropriate destructor. The elements of instances are pointers and there is no globally applicable destructor. While you might think that deletion is an appropriate behaviour std::vector::clear() has no idea who might own these these pointers. In general if you allocated the memory you should free it.
Try
for( std::vector<x*>::iterator it=instances.begin(); it!=instances.end(); ++it)
{
delete *it;
}
instances.clear();

Class creating multiple objects of another class at the same memory location (C++)

So, I've got this class that contains a vector of another class. Whenever I try to push a new object into this vector, it's creating that object at the same memory location each time.
The (hopefully) relevant code:
class FSM{
private:
std::vector<Node> nodeList;
int cap;
int obs;
int topNode;
public:
FSM(int nodeCap, int numObs){
cap = nodeCap;
obs = numObs;
topNode = -1;
}
bool addNode(){
if (isFull()) return false;
nodeList.push_back(Node(obs));
topNode++;
return true;
}
Now, if I create a stand-alone Node object in my main function and cout the &node, I get different memory locations. But the ones created in the FSM class are always the same. Also, if I change anything in one of the Nodes stored by the FSM class, it changes it for all of them. I have no idea what's going on.
EDIT: As requested, here is the Node class. Just gonna post the whole thing, not sure what is relevant.
class Node{
private:
std::vector<int> connects;
int action;
public:
Node(int numObs){
for(int i = 0; i < numObs; i++){
connects.push_back(-1);
}
srand(time(NULL));
}
void setConnections(std::vector<int> newVec){
for (int i = 0; i < connects.size(); i++){
connects[i] = newVec[i];
}
}
int getConnection(int index){
return connects[index];
}
std::vector<int> getConnectionList(){
return connects;
}
void setAction(int act){
action = act;
}
int getAction(){
return action;
}
void setRandomConnections(int numNodes){
for (int i = 0; i < connects.size(); i++){
connects[i] = rand() % numNodes;
}
}
};
EDIT the Second: Here's what my main is doing.
int main(){
FSM myFSM(5, 3);
while (!myFSM.isFull()){
myFSM.addNode();
std::cout << &myFSM.getTopNode(); // getTopNode() returns the most recent
// node.
}
}
If getTopNode does what I think it does, you're printing the address of a temporary object (aka a copy of the top node, not the top node itself). So that code is meaningless.
Here I've implemented a print function for the locations of the nodes in FSM:
void printNodeLocations()
{
for(Node& n : nodeList) { std::cout << &n << std::endl; }
}
And I get different ones as expected:
0x8ad3018
0x8ad301c
EDIT: I cannot reproduce your claim that changing one node changes all of them. See updated code
This line:
std::cout << &myFSM.getTopNode();
probably prints the address of a temporary object, not the actual object in the vector. This will be true if you're not returning by reference but rather by value.
So it's not weird if the temporary happens to be created at the same location each time, since after the temporary dies, its location in memory is free to be used again later.
In order to get the actual object rather than a copy of it, getTopNode() needs to do:
Node& FSM::getTopNode()
{
if (nodeList.empty()) {
// Up to you how to handle this error.
}
return nodeList.back();
}
Of course, if your current getTopNode() implementation actually already returns a pointer:
Node* FSM::getTopNode()
then your problem is that you're printing out the address of the pointer rather than the pointer itself. In that case you should print with:
std::cout << myFSM.getTopNode();
Nothing happens similar to yours.
#include <iostream>
#include <vector>
class Node{
private:
std::vector<int> connects;
int action;
public:
Node(int num){
for(int i = 0; i < num; i++){
connects.push_back(i);
}
}
std::vector<int> getConn()
{
return connects;
}
};
class FSM{
private:
std::vector<Node> nodeList;
public:
FSM(){}
void addNode(int size){
Node l(size);
std::cout<<"temp_address "<<&l<<"\n";
nodeList.push_back(l);//use of default copy constructor
}
void printList(){
std::vector<int> p;
for (int i=0; i<nodeList.size(); i++)
{
std::cout<<"Node_arr_num "<<i<<" mem_address "<<&nodeList[i]<<"\nConnections:";
p=nodeList[i].getConn();
for (int j=0; j<p.size(); j++)
std::cout<<" "<<p[j];
std::cout<<"\n";
}
}
};
int main()
{
FSM f;
f.addNode(5);
f.addNode(10);
f.addNode(3);
f.printList();
return 0;
}
Result:
temp_address 0xbfea7660
temp_address 0xbfea7660
temp_address 0xbfea7660
Node_arr_num 0 mem_address 0x8dab098
Connections: 0 1 2 3 4
Node_arr_num 1 mem_address 0x8dab0a8
Connections: 0 1 2 3 4 5 6 7 8 9
Node_arr_num 2 mem_address 0x8dab0b8
Connections: 0 1 2
Be careful with adding nodes later, when your app will grow. Temporary l object (ore your Node(obs)) must be copied with explicit copy constructor of class Node if Node will be more complex (contains fields with dynamic allocated memory).