Modifying value of object pointed by a shared pointer - c++

I have recently started working with shared pointers and need some help. I have a vector 1 of shared pointers to some objects. I need to construct another vector 2 of shared pointers to the same objects, so that modifying vector 2 would result in modification of vector 2.
This is how my code looks like:
This works fine
class A
{
public:
int a;
A (int x) {
a = x;
}
int print() {
return a;
}
};
int main()
{
shared_ptr<A> ab = make_shared<A>(100);
cout<< ab->print();
shared_ptr<vector<shared_ptr<A>>> vec1 = make_shared<vector<shared_ptr<A>>>(1);
shared_ptr<vector<shared_ptr<A>*>> vec2 = make_shared<vector<shared_ptr<A>*>>();
vec2->push_back(&(*vec1)[0]);
for (shared_ptr<A>* obj : *vec2) {
*obj = make_shared<A>(100);
}
cout << (*((*vec1)[0])).a; // Prints 100
return 0;
}
But this gives a SEGV at the last line since vec1 is not populated:
class A
{
public:
int a;
A (int x) {
a = x;
}
int print() {
return a;
}
};
int main()
{
shared_ptr<vector<shared_ptr<A>>> vec1 = make_shared<vector<shared_ptr<A>>>(1);
shared_ptr<vector<shared_ptr<A>>> vec2 = make_shared<vector<shared_ptr<A>>>();
vec2->push_back((*vec1)[0]);
for (shared_ptr<A> obj : *vec2) {
obj = make_shared<A>(100);
}
cout << (*((*vec1)[0])).a; // SIGSEGV
return 0;
}
I want to understand why vec1 was not populated in the 2nd one and also would like to know if there is any other way of doing this. Thanks!

The code for the setup described in the comments could be:
#include <vector>
#include <memory>
#include <iostream>
using namespace std;
struct A
{
int a;
A(int a): a(a) {}
};
int main()
{
auto p_vec1 = make_shared<vector<shared_ptr<A>>>();
auto p_vec2 = make_shared<vector<shared_ptr<A>>>();
for (int i = 0; i < 100; ++i)
p_vec1->push_back( make_shared<A>(i) );
for (int i = 0; i < 50; ++i)
p_vec2->push_back( (*p_vec1)[i * 2] );
(*p_vec1)[2]->a = 213;
std::cout << (*p_vec2)[1]->a << '\n'; // print 213
return 0;
}
In case you are unaware, the "outer" shared_ptr is unnecessary, you could just use two vectors .

Related

How to pass parameters in an objects of array? in c++

class A
{
int id;
public:
A (int i) { id = i; }
void show() { cout << id << endl; }
};
int main()
{
A a[2];
a[0].show();
a[1].show();
return 0;
}
I get an error since there is no default constructor.However thats not my question.Is there a way that ı can send parameters when defining
A a[2];
A good practice is to declare your constructor explicit (unless it defines a conversion), especially if you have only one parameter. Than, you can create new objects and add them to your array, like this :
#include <iostream>
#include <string>
class A {
int id;
public:
explicit A (int i) { id = i; }
void show() { std::cout << id << std::endl; }
};
int main() {
A first(3);
A second(4);
A a[2] = {first, second};
a[0].show();
a[1].show();
return 0;
}
However, a better way is to use vectors (say in a week you want 4 objects in your array, or n object according to an input). You can do it like this:
#include <iostream>
#include <string>
#include <vector>
class A {
int id;
public:
explicit A (int i) { id = i; }
void show() { std::cout << id << std::endl; }
};
int main() {
std::vector<A> a;
int n = 0;
std::cin >> n;
for (int i = 0; i < n; i++) {
A temp(i); // or any other number you want your objects to initiate them.
a.push_back(temp);
a[i].show();
}
return 0;
}

How to create a matrix of pointers using smart pointers for a class?

Let's say we have the following code in c-style
class Dog {
public:
void woof() {};
};
int main() {
Dog* mat[5][5];
mat[0][0] = new Dog();
mat[0][0]->woof();
}
How would you write it in cpp style using smart pointers? is the following is fine?
class Dog {
public:
void woof() {};
};
int main() {
std::unique_ptr<Dog> mat[5][5];
mat[0][0] = std::make_unique<Dog>();
mat[0][0]->woof();
}
or maybe even something such as:
class Dog {
public:
void woof() {};
};
int main() {
std::unique_ptr<std::unique_ptr<std::unique_ptr<Dog>[]>[]> mat = std::make_unique<std::unique_ptr<std::unique_ptr<Dog>[]>[]>(5);
for (int i = 0; i < 5; i++)
mat[i] = std::make_unique<std::unique_ptr<Dog>[]>(5);
mat[0][0] = std::make_unique<Dog>();
mat[0][0]->woof();
}
how can I do it in the most elegant and memory-efficient way?
If the dimensions are fixed, which I think they are, then you can use std::array. Then loop through and fill the elements with std::generate:
#include <iostream>
#include <array>
#include <algorithm>
#include <memory>
class Dog {
public:
void woof() { std::cout << "woof" << std::endl; };
};
int main() {
std::array<std::array<std::unique_ptr<Dog>, 5>, 5> matrix;
for (int x=0; x < 5; ++x)
{
std::generate(std::begin(matrix[x]), std::end(matrix[x]),
[]{ return std::make_unique<Dog>(); } );
}
matrix[0][0]->woof();
matrix[4][4]->woof();
return 0;
}
Demo

Whats the correct way of accessing the array through reference

How do i access the array in the main using the reference arrref
The memory leak in the code below is intended to know valgrind tool.But i am not able to compile the code below
#include <iostream>
int& func();
int main()
{
int &arrref = func();
std::cout<<arrref[1];//Error
std::cout<<&arrref[1];//Error
}
int& func()
{
int *a = new int[10];
for(int i = 0;i<10 ;++i)
a[i] = i*2;
return *a;
}
Thanks
The syntax needed is (&arrref)[1]. That refers to the second element of an array.
But make sure that the reference returned from func indeed refers to the first element of an array with sufficient number of elements.
To communicate clearly that func returns a reference to an array you may like to return a range, e.g.:
#include <iostream>
#include <boost/range/as_array.hpp>
boost::iterator_range<int*> func() {
static int array[2] = {1, 2};
return boost::as_array(array);
}
int main() {
auto array = func();
std::cout << array[0] << '\n';
std::cout << array[1] << '\n';
for(auto const& value: func())
std::cout << value << '\n';
}
Outputs:
1
2
1
2
Firstly it is not a good idea access local variables of one function in some other functions.
The function return type is int& which says that you want to return a reference to an int variable.
If you want to access the array local array 'a' then the function should be rewritten as -
#include <iostream>
int* func();
int main()
{
int *arrref = func();
std::cout<<arrref[1];//Error
std::cout<<&arrref[1];//Error
}
int *func()
{
int *a = new int[10];
for(int i = 0;i<10 ;++i)
a[i] = i*2;
return a;
}
Alternatively you can also use vectors -
#include<iostream>
#include<vector>
std::vector<int>& func();
int main()
{
std::vector<int>& arrref = func();
std::cout<<arrref[1];//Error
std::cout<<&arrref[1];//Error
}
std::vector<int>& func()
{
std::vector<int> a(10);
for(int i = 0;i<10 ;++i)
a[i] = i*2;
return a;
}

How can I pass an array of objects?

Here I have a very simple program. My aim is to let b equal c, that is to copy all the content of c into b. But I don't know how. The getdata() function returns a pointer pointing to array of objects c, but how can it be used to put c into b?
#include<iostream>
#include<stdlib.h>
using namespace std;
class A
{
public:
A(int i,int j):length(i),high(j){}
int length,high;
};
class B
{
private:
A c[3] = {A(9,9),A(9,9),A(9,9)};
public:
A* getdata()
{
return c;
}
};
int main()
{
A b[3]={A(0,0),A(0,0),A(0,0)};
B *x = new B();
cout<< x->getdata() <<endl;
cout << b[1].length<<endl;
return 0;
}
In modern C++, make yourself a favor and use a convenient container class to store your arrays, like STL std::vector (instead of using raw C-like arrays).
Among other features, std::vector defines an overload of operator=(), which makes it possible to copy a source vector to a destination vector using a simple b=c; syntax.
#include <vector> // for STL vector
....
std::vector<A> v; // define a vector of A's
// use vector::push_back() method or .emplace_back()
// or brace init syntax to add content in vector...
std::vector<A> w = v; // duplicate v's content in w
That's a possible partial modification of your code, using std::vector (live here on codepad):
#include <iostream>
#include <vector>
using namespace std;
class A
{
public:
A(int l, int h) : length(l), high(h) {}
int length, high;
};
class B
{
private:
vector<A> c;
public:
const vector<A>& getData() const
{
return c;
}
void setData(const vector<A>& sourceData)
{
c = sourceData;
}
};
int main()
{
vector<A> data;
for (int i = 0; i < 3; ++i) // fill with some test data...
data.push_back(A(i,i));
B b;
b.setData(data);
const vector<A>& x = b.getData();
for (size_t i = 0; i < x.size(); ++i) // feel free to use range-for with C++11 compilers
cout << "A(" << x[i].length << ", " << x[i].high << ")\n";
}
Instead of creating an array of A i.e. 'b' in main, create a pointer to A. And then initialize it by calling the getdata().
A *b;
B *x = new B();
b = x->getdata();
Here is an example
#include <iostream>
#include <algorithm>
class A
{
public:
A( int i, int j ) : length( i ), high( j ){}
int length, high;
};
class B
{
private:
A c[3] = {A(9,9),A(9,9),A(9,9)};
public:
A* getdata()
{
return c;
}
};
int main()
{
A b[3] = { A(0,0), A(0,0), A(0,0) };
B *x = new B();
A *c = x->getdata();
std::copy( c, c + 3, b );
for ( const A &a : b ) std::cout << a.length << '\t' << a.high << std::endl;
delete []x;
return 0;
}
The output is
9 9
9 9
9 9
Instead of standard algorithm std::copy you may use an ordinary loop. For example
for ( size_t i = 0; i < 3; i++ ) b[i] = c[i];

Vector subscript out of range when incrementing an int?

So strange situation, I am creating a list of structs, and then I am trying to update one of the list members with new values, and then move it back into the list.
I seem to be able to copy the values of the struct at iterator just fine, but when I attempt to update the value of the struct's member (using int++;) it throws an exception in the vector class of all things.
Any kind of explanation as to what might be happening here would be helpful.
struct Blob
{
int x;
int y;
};
list<Blob> blob;
// Add a Blob to blob using .push_back(); here
for(list<Blob>::iterator iterator=blob.begin(); iterator!=blob.end(); ++iterator)
{
Blob temp;
temp.x = ((Blob)*iterator).x;
temp.y = ((Blob)*iterator).y;
if (temp.x < 10 - 1)
temp.x++; /* Exception: vector: line 932 - "Vector subscript out of range" */
((Rain)*iterator) = temp;
}
When you want to update the existing value of object then take a reference of it. I have written a sample code to explain the same
#include<list>
#include<iostream>
using namespace std;
struct Test
{
int x;
int y;
};
int main()
{
list<Test> lTest;
int i = 0;
for(i=0;i<5;i++)
{
Test t1;
t1.x = i;
t1.y = i*i;
lTest.push_back(t1);
}
list<Test>::iterator lIter = lTest.begin();
for(;lIter != lTest.end();++lIter)
{
Test &t1 = *lIter;
cout<<"1 Val is:"<<t1.x<<"|"<<t1.y<<endl;
t1.x += 2;
t1.y += 2;
cout<<"2 Val is:"<<t1.x<<"|"<<t1.y<<endl;
}
lIter = lTest.begin();
for(;lIter != lTest.end();++lIter)
{
Test t1 = *lIter;
cout<<"3 Val is:"<<t1.x<<"|"<<t1.y<<endl;
}
return 0;
}
If you're writing a loop it's likely there's another way to do it. You can use std::for_each:
#include <list>
#include <algorithm>
struct Blob
{
int x;
int y;
};
void incrementXIfLessThanNine(Blob& blob)
{
if(blob.x < 9)
{
blob.x++;
}
}
int main()
{
std::list<Blob> blobs;
std::for_each(blob.begin(), blob.end(), incrementXIfLessThanNine);
return 0;
}
If you're using C++11:
#include <list>
struct Blob
{
int x;
int y;
};
int main()
{
std::list<Blob> blobs;
for(Blob& blob: blobs)
{
if(blob.x < 9)
{
blob.x++;
}
}
return 0;
}