Are structure members of structure passed by reference, passed ONLY by value? - c++

My module tries to do things along the lines of the following program: sub-functions try to modify a structure's elements and give it back to the function to whom the structure is passed by reference.
#include <iostream>
#include <vector>
using namespace std;
struct a
{
int val1;
vector<int> vec1;
};
struct a* foo();
void anotherfunc(struct a &input);
int main()
{
struct a *foo_out;
foo_out = foo();
cout<< "Foo out int val: "<< foo_out->val1<<"\n";
cout<< "Foo out vector size: "<< foo_out->vec1.size()<< "\n";
cout<< "Foo out vector value1: "<< foo_out->vec1.at(0)<< "\n";
cout<< "Foo out vector value2: "<< foo_out->vec1.at(1)<< "\n";
return 0;
}
struct a *foo()
{
struct a input;
input.val1=729;
anotherfunc(input);
return &input;
}
void anotherfunc(struct a &input)
{
input.vec1.push_back(100);
input.vec1.push_back(1000);
input.vec1.push_back(1024);
input.vec1.push_back(3452);
cout<< "Anotherfunc():input vector value1: "<< input.vec1.at(0)<< "\n";
cout<< "Anotherfunc():input vector value2: "<< input.vec1.at(1)<< "\n";
cout<< "Anotherfunc():input int val: "<< input.val1<< "\n";
}
I am expecting the main function to contain the modified integer value in structure (729), and also the vector values (100,10000,1024 and 3452). On the contrary, main has none of these values, and on g++, the program shows a strange behaviour: main() shows that there are 4 elements in the vector inside structure, but when trying to print the values, segfaults.
After some more thought, I assume my question is : "Are structure members of structure passed by reference, passed ONLY by value ?" Should I not expect that vector to have the values set by functions to whom the entire structure is passed by reference? Kindly help.
Vijay

struct a *foo()
{
struct a input;
input.val1=729;
anotherfunc(input);
return &input;
}
You are returning pointer on the local object (it will be destroyed on exit from function), so, there is dangling pointer here and your program has undefined behaviour.

As ForeEveR says, the pointer you are returning is pointing to memory which is no longer guaranteed to contain a valid object. If you want this behavior, allocate input on the heap as follows:
a * foo ()
{
a * input = new input;
input->val1 = 729;
anotherfunc (*input);
return input;
}
Now it is the responsibility of whoever calls foo to free this memory, for example
{
a * foo_out = foo();
// do stuff with foo_out
delete foo_out; foo_out = 0;
}
At some point you will realize that keeping track of who allocated which objects is tedious, when this happens you should look up "smart pointers".

First of all, there is nothing terribly magical about "structures" in C++ — you should treat them like any other type. In particular, you don't need to write the keyword struct everywhere.
So here's your code in more idiomatic C++ (also re-ordered to avoid those wasteful pre-declarations):
#include <iostream>
#include <vector>
using namespace std;
struct a
{
int val1;
vector<int> vec1;
};
void bar(a& input)
{
input.vec1.push_back(100);
input.vec1.push_back(1000);
input.vec1.push_back(1024);
input.vec1.push_back(3452);
cout << "bar():input vector value1: " << input.vec1.at(0) << "\n";
cout << "bar():input vector value2: " << input.vec1.at(1) << "\n";
cout << "bar():input int val: " << input.val1 << "\n";
}
a* foo()
{
a input;
input.val1=729;
bar(input);
return &input;
}
int main()
{
a* foo_out = foo();
cout << "Foo out int val: " << foo_out->val1 << "\n";
cout << "Foo out vector size: " << foo_out->vec1.size() << "\n";
cout << "Foo out vector value1: " << foo_out->vec1.at(0) << "\n";
cout << "Foo out vector value2: " << foo_out->vec1.at(1) << "\n";
}
Now, as others have pointed out, foo() is broken in that it returns a pointer to a local object.
Why all the pointer trickery? If you're worried about copying that vector, then you can dynamically-allocate the a object and use a shared pointer implementation to manage that memory for you:
void bar(shared_ptr<a> input)
{
input->vec1.push_back(100);
input->vec1.push_back(1000);
input->vec1.push_back(1024);
input->vec1.push_back(3452);
cout << "bar():input vector value1: " << input->vec1.at(0) << "\n";
cout << "bar():input vector value2: " << input->vec1.at(1) << "\n";
cout << "bar():input int val: " << input->val1 << "\n";
}
shared_ptr<a> foo()
{
shared_ptr<a> input(new a);
input->val1 = 729;
bar(input);
return input;
}
Otherwise, just pass it around by value.

Related

The actual and formal parameters of the array use the same block address, while the variables use different addresses

When using the address transfer of function, View address blocks of formal parameters and actual parameters, I find that the arguments and formal parameters of array share one address block, while the arguments and formal parameters of variables use two address block. What is the reason?
The code is as follows:
#include<iostream>
using namespace std;
void test(int *i,int * arr) {
cout << &i << endl;
cout << arr << endl;
}
int main() {
int i = 1, arr[2] = {1,2};
cout << &i << endl;
test(&i, arr);
cout << arr << endl;
system("pause");
return 0;
}
And this is the output:
0000008986B6FC54
0000008986B6FC30
0000008986B6FC78 //Arrays use the same space
0000008986B6FC78
You are passing pointers to the functions. The value of the pointers are not modified, ie in the function they point to the same objects as they do in main.
However, you are not printing what you think you print:
void test(int *i,int * arr) {
cout << &i << endl;
cout << arr << endl;
}
The pointer i gets the parameter &i (the i from main). Hence printing i in main will yield the same value as printing i in test. However, you are printing the adress of i in the function not the value of it. If you change your code to:
void test(int *i,int * arr) {
cout << &i << endl;
cout << i << endl;
cout << arr << endl;
}
You will notice the difference. I suggest you to rename at least one of the is in your code, because using same name for different entities can and does cause confusion. The i in test holds the value of the address of the i in main. That does not mean that they are the same, but rather i in test has the same value as &i in main.
In short: &i == &i but you expect &(&i) to be the same as &i.
There is no difference between passing a pointer to the int or passing a pointer to the first element of the array. From the point of view of the function they are both just pointers to int.
Note that test prints the value of arr but the location of i.
In test, &i is the location of its argument i.
That argument's value is the location of the i in main.
You will see this if you print i instead of &i.
arr, on the other hand, is implicitly converted into a pointer to its first element, and you are both passing &arr[0] to test to print, and printing &arr[0] in main.
Here is the same thing with explicit conversions and without using a function:
int main() {
int i = 1, arr[2] = {1,2};
cout << &i << endl;
// Create the "argument"...
int *p = &i;
// These two lines are 'test'...
cout << &p << endl;
cout << &arr[0] << endl;
// and this is after the function call.
cout << &arr[0] << endl;
}

Questions about the ownership transfer of unique_ptr

For the following code:
#include <memory>
#include <iostream>
#include <vector>
using namespace std;
struct pm
{
pm() : a(make_unique<vector<int>>(1, 10)){};
unique_ptr<vector<int>> a;
};
struct parms
{
parms() : a(make_unique<pm>()){};
unique_ptr<pm> a;
};
class test
{
public:
test() : p(make_unique<parms>()) {}
unique_ptr<const parms> getParms()
{
return move(p);
}
void setParms(int b)
{
p->a->a->push_back(b);
}
void pp()
{
cout << p->a->a->at(0) << "\n";
}
private:
unique_ptr<parms> p;
};
int main()
{
auto t = make_unique<test>();
t->pp();
cout << t->getParms()->a->a->at(0) << "\n";
cout << (t->getParms()==nullptr) << "\n"; ;
}
t->getParms() is a nullptr after we "cout << t->getParms()->a->a->at(0) << "\n";".
If we do the same thing for the ptr,
int main()
{
auto t = make_unique<test>();
t->setParms(5);
t->pp();
auto ptr = t->getParms();
cout << ptr->a->a->at(0) << "\n";
cout << (ptr==nullptr) << "\n"; ;
}
ptr is not a nullptr.
My question is: why cout t->getParms(), then t->getParms() is a nullptr but prt is not? Is it because of the life scope of unique_ptr? Or the temporary rvalue? What's the reason behind this behavior?
Your method getParams() transfers ownership to the caller.
unique_ptr<const parms> getParms()
{
return move(p);
}
Member is moved to the return value and now the caller owns the pointee. You are not storing the returned value here:
cout << t->getParms()->a->a->at(0) << "\n";
Though, even if you did, t does not own the param anymore, hence when you ask t again:
cout << (t->getParms()==nullptr) << "\n"; ;
It doesnt know about the param anymore.
In the second example you transfer ownership from t to ptr:
auto ptr = t->getParms();
Now ptr owns the param. And you can inspect the pointer or the value as often as you like:
cout << ptr->a->a->at(0) << "\n";
cout << (ptr==nullptr) << "\n"; ;
There is no transfer of ownership in those two lines.
What's the reason behind this behavior?
The reason, as stated above, is that getParams() transfers ownership to the caller. Thats rather uncommon for a getter method. Perhaps "stealer-method" would be a better name ;). If you don't want to give up ownership (and you are certain that the pointer is a valid one) you can simply return a reference:
const parms& getParms() const { return *p; }
My question is: why cout t->getParms(), then t->getParms() is a nullptr but prt is not?
t->getParms() transfers the ownership to the caller. This sets t->p to null. Since t->p no longer owns a pointer, there is nothing to transfer when you call t->getParms() a second time.
You never transferred ownership from ptr, so it hasn't been set to null.

Add an element to a vector inside a struct, from within another struct

This is most probably trivial and I'm confusing struct allocation and pointers somehow, I apologize for this. I have read answers to similar questions but it didn't help. The code is, as always, way more complicted, this is a reduction from 3000+ lines of code to the gist.
The output I expected was
prep 1
main 1
Instead, I get
prep 1
main 0
This is the code:
#include <iostream>
#include <vector>
using namespace std;
struct Entry
{
vector<int> list;
};
struct Registry
{
vector<Entry> entries;
void prep()
{
Entry* entry = new Entry();
entries.push_back(*entry);
entry->list.push_back(0);
cout << "prep " << entry->list.size() << "\n";
}
};
int main()
{
Registry registry;
registry.prep();
cout << "main " << registry.entries[0].list.size() << "\n";
return 1;
}
You don't store pointers in your vector<Entry> so you should not use new. Instead add a default constructed Entry using emplace_back.
A C++17 approach:
void prep()
{
Entry& entry = entries.emplace_back(); // returns a ref the added element
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
}
Prior to C++17:
void prep()
{
entries.emplace_back(); // does NOT return a ref the added element
Entry& entry = entries.back(); // obtain a ref to the added element
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
}
If you do want to create and maniplate your Entry before adding it to entries, you can do that too and then std::move it into entries.
void prep()
{
Entry entry;
entry.list.push_back(0);
cout << "prep " << entry.list.size() << "\n";
entries.push_back(std::move(entry)); // moving is a lot cheaper than copying
}
The problem is the order of the prep() function. If you change to push an element into the Element object, and then push it tho the entries vector, the behavior will be the expected.
void prep()
{
Entry* entry = new Entry();
entry->list.push_back(0);
entries.push_back(*entry);
cout << "prep " << entry->list.size() << "\n";
}
This is happening, because you uses a copy in the entries list.
It is also possible to store the pointer of the object therefore you can edit the actual instance after you pushed to the entries vector.
Edit:
As Ted mentioned, there is a memory leak, because the entry created with the new operator never deleted. Another approach could be to use smart pointers (however, in this small example it seems overkill, just use reference)
void prep()
{
std::unique_ptr<Entry> entry = std::make_unique<Entry>();
entry->list.push_back(0);
entries.push_back(*entry.get()); // get the pointer behind unique_ptr, then dereference it
cout << "prep " << entry->list.size() << "\n";
} // unique_ptr freed when gets out of scope
You need to change the implementation of prep():
void prep()
{
Entry entry;
entry.list.push_back(0);
entries.emplace_back(entry);
cout << "prep " << entries.back().list.size() << "\n";
}
There is no need to allocate a Entry on the heap just to make a copy of it.

Rcpp: Is a wrapping class the only way to preserve fundamental types pointed to by Xptr?

I have a fair bit of experience with R, but am only now getting down to the business of learning C++, so I beg forgiveness for any ensuing stupidity....
Given the following test.cpp file:
#include <Rcpp.h>
#include <string>
using namespace Rcpp;
using namespace std;
XPtr< double > getPtr(NumericVector x) {
double i;
i = REAL(x)[0];
XPtr< double > p(&i, false);
XPtr<double> checkP(p);
double checkV = *checkP;
cout << "Values within getPtr scope:" << endl;
cout << "Pointer address " << hex << checkP << endl;
cout << "Pointer value " << checkV << endl;
return p;
}
// [[Rcpp::export]]
void testPtr(NumericVector x){
XPtr<double> p(getPtr(x));
cout << "Values outside of getPtr scope:" << endl;
cout << "Pointer address " << hex << p << endl;
cout << "Pointer value " << *p << endl;
return;
}
The following R snippet demonstrates that the value pointed to by the Xptr "disappears" outside the getPtr function.
> library(Rcpp)
> Rcpp::sourceCpp(file="test.cpp")
>
> test <- c(35,28,16,52)
> testPtr(test)
Values within getPtr scope:
Pointer address 0x7ffd3763d790
Pointer value 35
Values outside of getPtr scope:
Pointer address 0x7ffd3763d790
Pointer value 6.95277e-310
But of course! Since that value is out of scope, this is expected behavior.
Alternatively, if I wrap the value in a class and use new, the object persists and I can retrieve my value outside the scope of the called function:
class Wrap {
public:
Wrap(double x) {
i = x;
}
double i;
};
XPtr< Wrap > getPtrW(NumericVector x) {
double i;
i = REAL(x)[0];
Wrap* w = new Wrap(i);
XPtr< Wrap > p(w, true);
return p;
}
// [[Rcpp::export]]
void testWrappedPtr(NumericVector x){
XPtr<Wrap> wp(getPtrW(x));
Wrap w = *(wp);
cout << "Wrapped value " << w.i << endl;
return;
}
Then this demonstrates that the value persists as desired:
> testWrappedPtr(test)
Wrapped value 35
My questions (at last) are these: (1) Is this (i.e. wrapping in a class) the only way to hang on to values of variables that are fundamental types and not malloc'd or new'd and (2) if not, are any of the alternative ways "better" or "preferred"?
Thanks in advance!

boost multiarray as class member is not filled

I'm trying to use boost to create a multidimensional array and I want said array to be a member of some class.
However I find two problems with it:
1 - I need to declare the size of the array with
boost::extents[2][2]
Everytime I want to use the array. Otherwise I get the following error:
a.out: /usr/include/boost/multi_array/base.hpp:136: Referenceboost::detail::multi_array::value_accessor_n<T, NumDims>::access(boost::type<Reference>, boost::detail::multi_array::value_accessor_n<T, NumDims>::index, TPtr, const size_type*, const index*, const index*) const [with Reference = boost::detail::multi_array::sub_array<double, 1ul>; TPtr = double*; T = double; long unsigned int NumDims = 2ul; boost::detail::multi_array::value_accessor_n<T, NumDims>::index = long int; boost::detail::multi_array::multi_array_base::size_type = long unsigned int]: Assertion `size_type(idx - index_bases[0]) < extents[0]' failed.
2 - Ok, maybe this is just part of how multidimensional arrays work in C++ with Boost, I'm going to write my code accepting every function "declares" the array. However, if I do this I find the array is empty.
Here's a snippet of code that reproduces this problem. During the "construction" of the class the array should be filled. However, the line
cout << "Result: " << testing.getArrayMember(0,1) << endl;
outputs "Result: 0".
#include <iostream>
#include "boost/multi_array.hpp"
typedef boost::multi_array<double, 2> dbl_array;
using namespace std;
class TestClass {
public:
dbl_array darray;
TestClass(double x);
void fillArray(double x);
double getArrayMember(int i, int j);
};
TestClass::TestClass(double x) {
dbl_array darray(boost::extents[2][2]);
cout << "Class constructor called" << endl;
fillArray(x);
}
void TestClass::fillArray(double x) {
cout << "Filling array" << endl;
dbl_array darray(boost::extents[2][2]); // Without this line, the code fails at runtime
darray[0][0] = x;
darray[1][0] = 2.0*x;
darray[0][1] = 3.0*x;
darray[1][1] = 4.0*x;
cout << "Array filled" << endl;
}
double TestClass::getArrayMember(int i, int j) {
dbl_array darray(boost::extents[2][2]); // Without this line, the code fails at runtime
return darray[i][j];
}
int main() {
TestClass testing = TestClass(5.0);
// The result is 0 in the end
cout << "Result: " << testing.getArrayMember(0,1) << endl;
return 0;
}
What am I doing wrong here?
Option 1 is to use an initialisation list:
TestClass::TestClass(double x) : darray(boost::extents[2][2]) {
cout << "Class constructor called" << endl;
fillArray(x);
}
Since otherwise the member of the class darray is created using the default constructor and not through your line
dbl_array darray(boost::extents[2][2]);
as you believe.
This is the same answers as given in initialize boost::multi_array in a class
However, I want to add the following bit, which I think it is relevant in this situation:
It might be necessary for you to generate the array after performing some kind of operation in the constructor of your class. You can achieve this using "resize" after the array has been created by the default constructor.
Ie, instead of
TestClass::TestClass(double x) {
dbl_array darray(boost::extents[2][2]);
cout << "Class constructor called" << endl;
fillArray(x);
}
you could have
TestClass::TestClass(double x) {
darray.resize(boost::extents[2][2]);
cout << "Class constructor called" << endl;
fillArray(x);
}