nested boost::shared_ptr use_count not updating - c++

I have a nested boost::shared_ptr which was occasionally getting destroyed when getting assigned to another one and going out of scope. I figured out that the use_count was not updating unless I copy the pointer to a temp. The code is self-explanatory. In the first for-loop, the use_count doesn't update, whereas it updates on the other.
#include <vector>
#include <boost/shared_ptr.hpp>
#include <iostream>
using namespace std;
int main(int argc, char const *argv[])
{
typedef int T;
typedef std::vector<T> content_1d_t;
typedef boost::shared_ptr<content_1d_t> storage_1d_t;
typedef std::vector<storage_1d_t> content_2d_t;
typedef boost::shared_ptr<content_2d_t> storage_2d_t;
int dim1 = 10;
int dim2 = 1;
content_2d_t* content_1 = new content_2d_t();
content_1->reserve(dim2);
storage_2d_t storage_1(content_1);
for (int i = 0; i < dim2; ++i)
{
storage_1->push_back(storage_1d_t(new content_1d_t(dim1)));
}
//content_2d_t* content_2 = new content_2d_t(dim2);
storage_2d_t storage_2 = storage_1;
for (int i = 0; i < dim2; ++i)
{
cout<< "use count before : "<< storage_1->operator[](i).use_count()<<endl;
storage_2->operator[](i) = storage_1->operator[](i);
cout<< "use count after: "<< storage_1->operator[](i).use_count()<<endl;
}
for (int i = 0; i < dim2; ++i)
{
cout<< "use count before : "<< storage_1->operator[](i).use_count()<<endl;
storage_1d_t ref = storage_1->operator[](i);
storage_2->operator[](i) = ref;
cout<< "use count after: "<< storage_1->operator[](i).use_count()<<endl;
}
/* code */
return 0;
}
output
use count before : 1
use count after: 1
use count before : 1
use count after: 2

Since you do storage_2d_t storage_2 = storage_1; obviously, assigning the elements directly back onto themselves should not increase use counts.
I the second loop you print the use count during the time where you hold the temporary copy (ref). Making it explicit, you can see that indeed - as expected - the "after" count is not actually higher:
for (int i = 0; i < dim2; ++i) {
cout << "use count before : " << (*storage_1)[i].use_count() << endl;
{
storage_1d_t ref = (*storage_1)[i];
(*storage_2)[i] = ref;
cout << "use count during: " << (*storage_1)[i].use_count() << endl;
}
cout << "use count after: " << (*storage_1)[i].use_count() << endl;
}
Now prints
use count before : 1
use count during: 2
use count after: 1
See it Live On Coliru
Brainwave Did you mean to deep-clone storage_1 into storage_2? It appears you have been confused by the fact that your outer storage_2d_t is also a shared pointer and hence you refer to the same vector by reference.
storage_2d_t storage_2 = boost::make_shared<content_2d_t>(*storage_1);
// or
storage_2d_t storage_2 = boost::make_shared<content_2d_t>(storage_1->begin(), storage_1->end());

Related

Want to print next biggest number

So Here is the question:
Consider a class named Job that has deadline as a data member and relevant getter/setter
method(s). Assume you have to schedule two most earliest jobs on the basis of their deadlines. That is,
if there are three jobs in the system with deadlines (deadline1, deadline2, and deadline3, respectively)
then the system should report the top two earliest jobs (with smallest deadline value). You might need
to find the deadline with smallest and second most smallest value.
Here is my code:
#include<iostream>
using namespace std;
class job
{
private:
int Deadline;
public:
static int i;
void setDeadline(int a);
int getDeadline();
};
void job::setDeadline(int a)
{
Deadline = a;
cout << "Job " << i << " Has Deadline " << Deadline << endl;
}
int job::getDeadline()
{
return Deadline;
}
int job::i = 1;
int main()
{
job job1, job2, job3, job4, job5, job6, job7, job8, job9, job10, count;
job1.setDeadline(5);
count.i++;
job2.setDeadline(3);
count.i++;
job3.setDeadline(6);
count.i++;
job4.setDeadline(12);
count.i++;
job5.setDeadline(31);
count.i++;
job6.setDeadline(20);
count.i++;
job7.setDeadline(19);
count.i++;
job8.setDeadline(2);
count.i++;
job9.setDeadline(8);
count.i++;
job10.setDeadline(7);
int array[10] = { job1.getDeadline(), job2.getDeadline(),job3.getDeadline(),job4.getDeadline(),job5.getDeadline(),job6.getDeadline(),job7.getDeadline(),job8.getDeadline(),job9.getDeadline(),job10.getDeadline() };
int temp = array[0], store = 0, first = 0, second = 0;
for (int i = 0; i <= 9; i++)
{
if (temp > array[i])
{
temp = array[i];
}
}
for (int i = 0; i <= 9; i++)
{
if (temp == array[i])
{
first = i + 1;
break;
}
}
temp = array[0];
for (int i = 0; i <= 9; i++)
{
if (temp > array[i])
{
temp = array[i];
}
}
for (int i = 0; i <= 9; i++)
{
if (temp == array[i])
{
second = i + 1;
}
}
cout << "\nJob " << first << " and Job " << second << " are earliest";
return 0;
}
the problem I am facing is that both times it print the first smallest value. I want to print first 2 smallest value. How can I do that?
When you look for the first value, you go through the array and find the job with the lowest deadline and fill "first" with the job id (by the way, if you want to relate the "job id" to the index, personally I would make the variables zero-based, so job0, job1 and so on up to job9)
When you look for the second value, you do the exact same operations so the job you find is again the job with the lowest deadline and use that info to fill "second".
So, as you do the exact same thing both times, you are getting the exact same value for both. When you search for the second value you should take "first" into account so that you ignore the job that has already been used for "first" and not update "temp" in that case (this is a little bit easier if you name the jobs starting with zero because you don't have to constantly add one to the index).
the problem I am facing is that both times it print the first smallest value. I want to print first 2 smallest value. How can I do that?
With your solution: By creating another temp array with the first element removed you already discovered.
I wrote you as a minimal executable example using a vector of pairs since you didn't mention restrictions or anything - that is the most elegant solution I am able to come up with:
#include <iostream>
#include <vector>
#include <string>
bool sortVecBySec(const std::pair<std::string, int> &a,
const std::pair<std::string, int> &b)
{
return (a.second < b.second);
}
int main()
{
//Driver function to sort the vector elements by
//the second element of pairs
std::vector<std::pair <std::string,int>> v;
std::string job[10];
int deadline[10] = {5,3,6,12,31,20,19,2,8,7};
int n = sizeof(job)/sizeof(job[0]);
//Propagate string array
for(int i{}; i < 10;++i){
job[i] = "Job " + (std::to_string(i+1));
}
//Enter values in vector of pairs
for(int i{}; i<n; ++i){
v.push_back(make_pair(job[i],deadline[i]));
}
//Printing the vector of pairs
std::cout << "Vector of pairs as it is before\n";
for(int i{}; i< n; i++){
std::cout << v[i].first << " = " <<v[i].second << '\n';
}
//Using sort() function to sort by 2nd element of pairs
sort(v.begin(), v.end(),sortVecBySec);
//Printing the vector of pairs
std::cout << "\nVector of pairs from shortest to longest\n";
for(int i{}; i< 2; i++){
std::cout << v[i].first << " = " <<v[i].second << '\n';
}
std::cin.get();
return 0;
}
If you want to print all jobs, just use the n variable in the last print section instead of 2.
I think that should help you and shouldn't be to hard to parse it in a class.
First, you can save an extra round by saving the index right there, when you locate the earliest deadline
for (int i = 0; i <= 9; i++)
{
if (temp > array[i])
{
temp = array[i];
first = i + 1;
}
}
When searching for the next higher deadline value, you must take first into account. Both for the start value, and later when comparing with other values
temp = first > 1 ? array[0] : array[1];
for (int i = 0; i <= 9; i++)
{
if (temp > array[i] && array[i] > array[first])
{
temp = array[i];
second = i + 1;
}
}
Be aware, that this does not work properly, when you have multiple equal values.
For this case, compare the index values instead, e.g.
if (temp > array[i] && i != first)
{
temp = array[i];
second = i + 1;
}

Size of queue is reset to 0 in for statement c++

I dont now how to add 2 different data from vector_data to hpp_DE. In the second iteration (i = 1), size of hpp_DE is reset to 0.
struct Instr;
queue <struct> hpp_DE;
queue <struct> vector_data;
//size of vector is 2;
for (int i = 0; i <= vector_data.size(); i++) {
Instr = vector_date.front();
vector_data.pop();
hpp_DE.push(Instr);
}
It should add in queue hpp_DE two values, but I only get one value; the second is added. The first value from vector_data is gone from hpp_DE. Why is that happening?
in
for (int i = 0; i <= vector_data.size(); i++) {
Instr = vector_date.front();
vector_data.pop();
hpp_DE.push(Instr);
}
the size of vector_data changes because of the pop and at the same time you increment i to compare it to the (modified) size, this is wrong if you want to copy all the elements.
You use struct as a type, strange
vector_date must be vector_data
With that :
int main()
{
queue <int> hpp_DE;
queue <int> vector_data;
vector_data.push(1);
vector_data.push(2);
for (int i = 0; i <= vector_data.size(); i++) {
int v = vector_data.front();
vector_data.pop();
hpp_DE.push(v);
}
cout << hpp_DE.size() << ':';
while (!hpp_DE.empty()) {
cout << ' ' << hpp_DE.front();
hpp_DE.pop();
}
cout <<endl;
}
Compilation and execution :
/tmp % g++ -pedantic -Wextra v.cc
v.cc: In function 'int main()':
v.cc:13: warning: comparison between signed and unsigned integer expressions
/tmp % ./a.out
2: 1 2
(Use size_t rather than int for the index to remove the warning)
But with
#include <queue>
#include <iostream>
using namespace std;
int main()
{
queue <int> hpp_DE;
queue <int> vector_data;
vector_data.push(1);
vector_data.push(2);
vector_data.push(3);
vector_data.push(4);
vector_data.push(5);
for (int i = 0; i <= vector_data.size(); i++) {
int v = vector_data.front();
vector_data.pop();
hpp_DE.push(v);
}
cout << hpp_DE.size() << ':';
while (!hpp_DE.empty()) {
cout << ' ' << hpp_DE.front();
hpp_DE.pop();
}
cout <<endl;
}
that prints 3: 1 2 3
If the goal it to copy all just loop while vector_data is not empty to do the copy, or just assign one into the other ?

Trying to pass an array of structures but I get a "cannot convert 'struct' to 'struct*' error

I keep getting this error when I try to pass this array of structures into the function AthleticContest():
cannot convert 'person' to 'person*'
Can someone please tell me what I am doing wrong? Am I passing the wrong thing into the function?
struct person
{
int athletic;
int smarts;
int spirit;
int contestVal;
};
int AthleticContest(person subjects[])
{
cout << "Athletic Contest!!!" << endl << endl;
for (int hh = 0; hh < 3; hh++)
{
int result = subjects[hh].athletic;
subjects[hh].contestVal = result;
cout << "Contestant # " << (hh+1) << ") " << subjects[hh].contestVal << endl;
}
int winner;
int tempWin = -1;
for (int hh = 0; hh < 3; hh++)
{
if (subjects[hh].contestVal > tempWin)
{
tempWin = subjects[hh].contestVal;
winner = hh;
}
else if (subjects[hh].contestVal == tempWin)
{
if (randomInt() > 4)
winner = hh;
}
}
cout << "Winner is Contestant # " << (winner+1) << endl;
return winner;
}
int main()
{
person subject[10];
subject[0].athletic = 5;
subject[0].smarts = 3;
subject[0].spirit = 1;
subject[1].athletic = 1;
subject[1].smarts = 3;
subject[0].spirit = 5;
subject[1].athletic = 3;
subject[1].smarts = 5;
subject[0].spirit = 1;
AthleticContest(subject[2]);
}
The error
When you call your function in main():
AthleticContest(subject[2]);
you pass as argument a single person, which is the third element of your array (the element with index 2). So the compiler understands that you try to pass this object of type person.
But your function's parameter is declared to be of type array of undetermined size (i.e. person[]). C++ treats such array arguments as if they were a pointer (to their first element), so like person*.
This is why you get this error message: these types are incompatible
The solution
To get rid of this error, a solution would be to pass a pointer to a subject, for example:
AthleticContest(&subject[2]); // passes the pointer to the third element
// or
AthleticContest(subject); // passes the pointer to the first element of the original array
However, be very careful, because your function has a very risky design: you expect the argument to be a pointer to an array of at least 3 consecutive elements. So if you call it with &subject[8], it would try to access subject[10] which would be out of bounds. If you'd call with &subject[2] it would work with garbege information, since you have initalized only the first two elements, and not the 3rd, 4th and 6th.
A better solution
It is not clear, why you do the constest just with 3 elements. A better option would be the caller to say how many contestant shall be used (the caller know the size of the array).
In main():
AthleticContest(subject, 2); // 2 is the number of contestants in array
Your function would be defined as:
int AthleticContest(person subjects[], int participants)
{
cout << "Athletic Contest!!!" << endl << endl;
for (int hh = 0; hh < participants; hh++)
...
for (int hh = 0; hh < participants; hh++)
...
}
A much better solution
You'd better go for std::vector instead of C++ arrays. They can behave like arrays:
vector<person> subject(2); // create a vector of 2 items
subject[0].athletic = 5;
...
But they are much more convenient because they can have a dynamic size and grow as you add new participants:
person hbolt = {4, 2, 1, 0};
subject.emplace_back (hbolt); // one more participant
AthleticContest(subject);
Your function could get the vector by reference or by value. Let's take by reference, since you intend to modify its content and could possibly want this modified data after the return:
int AthleticContest(vector<person> &subjects)
{
...
}
The big advantage, is that you can always know the size of the vector:
for (int hh = 0; hh < subjects.size(); hh++)
...
Here is an online demo.
Of course, if you don't want to take all the participants in the vector, you'd have to think about your function's argument(s): would you prefer a second argument n and always take the n first elements of the vector ? Or would you prefer n participants but start at an arbitrary offset ? In both case, you'd be wise to check that your indexing never goes out of bounds.
One thing you need to change to compile: You're passing a reference to a single element of the array instead of the array itself.
One more thing you might want to check is to change your signature for AthleticContest() so it'll be the right one in C++ to receive fixed-sized array or person as a parameter.
When fixed to compile, and you're code looks like this:
#include <iostream>
using namespace std;
struct person
{
int athletic;
int smarts;
int spirit;
int contestVal;
};
template <std::size_t size>
int AthleticContest(person (&subjects)[size])
{
cout << "Athletic Contest!!!" << endl << endl;
for (int hh = 0; hh < 3; hh++)
{
int result = subjects[hh].athletic;
subjects[hh].contestVal = result;
cout << "Contestant # " << (hh+1) << ") " << subjects[hh].contestVal << endl;
}
int winner;
int tempWin = -1;
for (int hh = 0; hh < 3; hh++)
{
if (subjects[hh].contestVal > tempWin)
{
tempWin = subjects[hh].contestVal;
winner = hh;
}
else if (subjects[hh].contestVal == tempWin)
{
if (5 > 4)
winner = hh;
}
}
cout << "Winner is Contestant # " << (winner+1) << endl;
return winner;
}
int main()
{
person subject[10];
subject[0].athletic = 5;
subject[0].smarts = 3;
subject[0].spirit = 1;
subject[1].athletic = 1;
subject[1].smarts = 3;
subject[0].spirit = 5;
subject[1].athletic = 3;
subject[1].smarts = 5;
subject[0].spirit = 1;
AthleticContest(subject);
}

Locating a Segmentation Fault

I have the fallowing code. I read the guide for what a segmentation fault is, but I'm not 100% sure where its actually happening within my code. It works until I start working with the dynamic array (histogram), more specifically at the //set all initial values to be zero. Within that mess after I'm not sure. Thanks!
The instructor asked to "Use a dynamic array to store the histogram.", Which I think is my issue here.
-Solved-
thanks for the help, the error was in how I initialized the array pointer
rather than
const int hSize = 10;
IntArrayPtr histogram;
histogram = new int[hSize];
I used
const int hSize = 10;
int hValues[hSize] = { 0 };
IntArrayPtr histogram;
histogram = hValues;
Which worked as the instructor wanted.
#include <iostream>
#include <vector>
using namespace std;
typedef int* IntArrayPtr;
int main() {
vector<int>grades;
int newGrade;
cout << "Input grades between 0 and 100. Input -1 to calculate histogram: " << endl;
cin >> newGrade;
grades.push_back(newGrade);
while (newGrade > 0) {
cin >> newGrade;
while (newGrade > 100) {
cout << "less than 100 plz: ";
cin >> newGrade;
}
grades.push_back(newGrade);
}
grades.pop_back();
int size = grades.size();
cout << "Calculating histogram with " << size << " grades." << endl;
//Create dynamic array for the histogram of 10 sections.
const int hSize = 10;
IntArrayPtr histogram;
histogram = new int[hSize];
}
//Make the historgram
int stackValue = 0;
for (int j = 0; j < hSize; j++) {
//Loop through the grade vector slots
for (int i = 0; i < size; i++) {
int testValue = grades[i];
//If the grade at the index is between the stack values of the histogram add one to the value of the slot
if (testValue > stackValue && testValue < stackValue + 10) {
histogram[j]++;
}
}
//After looping through the vector jump up to the next histogram slot and corresponding stack value.
stackValue += 10;
}
//Histogram output. Only output the stacks with values
for (int i = 0; i < 10; i++) {
if (histogram[i] != 0) {
cout << "Number of " << (i + 1) * 10 << "'s: " << histogram[i];
}
}
return 0;
}
Working Code:
#include <iostream>
#include <vector>
using namespace std;
typedef int* IntArrayPtr;
int main() {
vector<int>grades;
int newGrade;
cout << "Input grades between 0 and 100. Input -1 to calculate histogram: " << endl;
cin >> newGrade;
grades.push_back(newGrade);
while (newGrade > 0) {
cin >> newGrade;
while (newGrade > 100) {
cout << "less than 100 plz: ";
cin >> newGrade;
}
grades.push_back(newGrade);
}
grades.pop_back();
int size = grades.size();
cout << "Calculating histogram with " << size << " grades." << endl;
//Create dynamic array for the histogram of 10 sections.
const int hSize = 10;
int hValues[hSize] = { 0 };
IntArrayPtr histogram;
histogram = hValues;
//Make the historgram
int stackValue = 0;
for (int j = 0; j < hSize; j++) {
//Loop through the grade vector slots
for (int i = 0; i < size; i++) {
int testValue = grades[i];
//If the grade at the index is between the stack values of the histogram add one to the value of the slot
if (testValue > stackValue && testValue < stackValue + 10) {
histogram[j]++;
}
}
//After looping through the vector jump up to the next histogram slot and corresponding stack value.
stackValue += 10;
}
//Histogram output. Only output the stacks with values
for (int i = 0; i < 10; i++) {
if (histogram[i] != 0) {
cout << "Number of " << (i + 1) * 10 << "'s: " << histogram[i] << endl;
}
}
return 0;
}
histogram is a pointer, not an array.
While
int histogram[hSize] = {0};
would create a zero-initialised array, your
histogram = { 0 };
does not set any elements to zero (it couldn't, because histogram points to one int, not many).
The braces are ignored – a pretty confusing behaviour inherited from C – and it is equivalent to
histogram = 0;
that is,
histogram = nullptr;
You want
int* histogram = new int[hSize]();
The parentheses value-initialises the array, and in turn its elements.
Value-initialising integers sets them to zero.
(By the way: the habit of typedeffing away asterisks causes more problems than it solves. Don't do it.)
Seg faults are problems with accessing regions of memory you don't have access to, so you need to look at your use of pointers. It often means you have a pointer with a bad value that you just dereferenced.
In this case, the problem is this line:
histogram = { 0 };
This is not setting the histogram values to zero as you think: it's resetting the historgram pointer to zero. Then you later dereference that pointer causing your SegFault (note that this line doesn't even compile with clang, so your compiler isn't helping you any on this one).
Changing that line to:
memset(histogram, 0, hSize);
Will sort the problem in this case.
More generally, to diagnose a segfault there are two tricks I use regularly (though avoidance is better than cure):
Run the program under a debugger: the debugger will likely stop the program at the point of the fault and you can see exactly where it failed
Run the program under Valgrind or similar - that will also tell you where the error surfaced but in more complex failures can also tell you where it was caused (often not the same place).

Sorting my 2d array in c++

My homework program has to write random numbers for arrival time and burst time into a file. Then after they are written, it reads the file and sorts the contents.
I figured setting up a 2d array would be the easiest way for me to go about this. But I am unsure on how to implement my sort so that if an arrival time swaps places then burst time of that arrival goes along for the ride.
I feel like I worded that poorly, but a basic example would be:
array[3][10] > array[2][23]
So since second array has an earlier arrival time I need both its arrival 2 and its burst 23 to move before array[3][10], but I need this do that and compare 100 inputs.
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <fstream>
const int max = 100;
using namespace std;
int main()
{
multimap<int [][]> myMap;
int randomBurst[max];
int arrivalTime[max];
int line[max][2];
int first = 0;
for (int i = 0; i < 100; i++)
{
if (i < 100)
{
ofstream write("Schedule.txt", ios::app);
randomBurst[i] = rand() % 1000;
arrivalTime[i] = rand() % 1000;
write << arrivalTime[i] << " " << randomBurst[i] << endl;
}
}
ifstream read("Schedule.txt");
for (int i = 0; i <= max; i++)
{
for (int j = 0; j < 2; j++)
{
read >> line[i][j];
cout << line[i][j] << " " ;
}
cout << endl;
}
cout << endl;
cout << endl;
for (int i = 0; i <= max; i++)
{
for (int j = 0; j < 2; j++)
{
myMap.insert(pair<int[][]>(line[i][j]);
}
cout << endl;
}
system("pause");
return 0;
}
My code sets up my array correctly after it reads the written file content, but I'm kind of lost what I should implement for a sort.
Well coming forward with this, mainly left that comment to be able to find this question faster on my laptop.
Like I said in the comment, if you want a presorted, by key value 2D "array", the quickest manner in which you could do this is with the map container., and if you really need the internal points to be ordered, and you will be using multiple entries within it, lets say entries 2,30 2,12 ... You could either build a map of vectors, or arrays, or use a Multimap. Not too sure of this data structure, as I have never really had a reason to use it as of yet. Referenced here http://www.cplusplus.com/reference/map/multimap/
The above will provide you with the sorting done for you, and the reason why I recommended a vector is the lack of order within it, and not sure if the 'bursts?' are to be ordered as well.
EDIT:
Forgot to mention, that a map will not hold more than one key of any given value, so if you are, again, inputting multiple points a above, then you will. if implementing things as you were before, overwrite things.
EDIT:
So this is more or less the fix I think I have, but you are working around this in a very indirect manner, that is hard to follow honestly.
#include <map>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <fstream>
using namespace std;
const int MAX = 100;
int main()
{
multimap<int,int> myMap;
int randomBurst[100];
int arrivalTime[100];
int line[100][2];
int first = 0;
for (int i = 0; i < 100; i++)
{
if (i < 100)
{
ofstream write("Schedule.txt", ios::app);
randomBurst[i] = rand() % 1000;
arrivalTime[i] = rand() % 1000;
write << arrivalTime[i] << " " << randomBurst[i] << endl;
}
}
ifstream read("Schedule.txt");
for (int i = 0; i <= 100; i++)
{
for (int j = 0; j < 2; j++)
{
read >> line[i][j];
cout << line[i][j] << " " ;
}
cout << endl;
}
// cout << endl;
// cout << endl;
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 2; j++)
{
//Attain the value in the index, and the held value within it.
myMap.insert(pair<int, int> (line[i][j], line[i][j]));
}
cout << endl;
}
// system("pause");
return 0;
This fixes the insertion point, just because you give it an array it does not mean that the program will take that as a pair, as the first index is a point to another array in itself. And so on. I recommend starting off wiht a map object instead, as the multimap makes things a bit annoying, if you are familiar with the vector containers then use that instead within the map to log multiple values.