Can anyone tell me whether this is safe and defined:
class RefClass
{
public:
RefClass(int i) { this->i = i; }
int& GetRef() { return i; }
private:
int i;
};
RefClass rc(10);
int* refp;
{
refp = &rc.GetRef();
}
*refp = 20;
Specifically I am concerned with the lifetime of the returned reference in the nested scope and whether it can be referenced in that scope and then later dereferenced as an lvalue after that scope has dissolved.
This code compiles and runs as expected in VS2012, but that doesn't mean it will in the next version, so I am trying to find a definitive answer.
Yes, that's fine.
The returned reference is a temporary, lasting until the end of the statement containing the function call. It's used within its lifetime to set refp to point to its target, rc.i. It's not needed to dereference the pointer after that.
The only danger is if the object might be destroyed, leaving the pointer dangling:
int* refp;
{
RefClass rc(10);
refp = &rc.GetRef();
} // rc is destroyed here
*refp = 20; // BOOM!!!
Yep, this is all right. You'd have issues in the following case:
int* refp;
{
RefClass rc(10);
refp = &rc.GetRef();
}
*refp = 20;
Related
I understand the concept of references in C++, and I understand what they do when used in function parameters, but I am still very much confused on how they work with return types.
For example, when used in parameters, this code:
int main (void) {
int foo = 42;
doit(foo);
}
void doit (int& value) {
value = 24;
}
is similar to this code:
int main (void) {
int foo = 42;
doit(&foo);
}
void doit (int* value) {
*value = 24;
}
(knowing that the compiler will automatically put an asterisk in front of value every time it is used in the first code sample of doit, but in the latter you'd have to put the asterisk in yourself every time you try to use value)
So when used as a reference what does this next code (using reference in a return type) translate to? Does it return a pointer to an int? Or would it just return an int?
int main (void) {
int* foo = /*insert useful place in memory*/;
foo = doit(foo);
}
int& doit (int* value) {
//insert useful code
}
It means you return by reference, which is, at least in this case, probably not desired. It basically means the returned value is an alias to whatever you returned from the function. Unless it's a persistent object it's illegal.
For example:
int& foo () {
static int x = 0;
return x;
}
//...
int main()
{
foo() = 2;
cout << foo();
}
would be legal and print out 2, because foo() = 2 modifies the actual value returned by foo.
However:
int& doit () {
int x = 0;
return x;
}
would be illegal (well, accessing the returned value would), because x is destroyed when the method exits, so you'd be left with a dangling reference.
Returning by reference isn't common for free functions, but it is for methods returning members. For example, in the std, the operator [] for common containers return by reference. For example, accessing a vector's elements with [i] returns an actual reference to that element, so v[i] = x actually changes that element.
Also, I hope that "is essentially equal to this code" means that they're semantically sort of (but not really) similar. Nothing more.
It means that you return a pointer to the memory address where the correspondent data is, instead of the very data.
Assuming this code (to make it comparable to the first example) :
int main (void) {
int* foo = /*insert useful place in memory*/;
*foo = doit(foo);
}
int& doit (int* value) {
*value = 24;
return *value;
}
The int& is not really useful as a return type in this case, because it provides access to the variable in memory (of which you pass the pointer to the function).
Does it return a pointer to an int? Or would it just return an int?
No, it returns a reference to an int. If you want, you can look at it as a pointer which can not be nullptr.
Hmm, the best way to know the answer is to have a try...
Your codes will not pass type check, because doit will return a reference of int while you accept the return value as a pointer of int.
You can have a look at this:
#include<iostream>
using namespace std;
int& doit (int* value) {
value[0] = 3;
return value[4];
}
int main (void) {
int* foo = new int[10];
for (int i=0; i<10; i++)
foo[i] = i;
int& bar = doit(foo);
cout<<bar<<endl;
for (int i=0; i<10; i++)
cout<<foo[i]<<" ";
cout<<endl;
bar = 12;
for (int i=0; i<10; i++)
cout<<foo[i]<<" ";
cout<<endl;
return 0;
}
The variable "bar" will accept the return value, and it can be used change the content of "foo". As is mentioned by Luchian, it maybe dangerous to return a reference from the function, because the later codes might modify a value which is in the stack.
I have one question.
Is it ok to use pointer vector as reference vector?
Struct Child
{
int n;
void func(int _n)
{
n = _n;
};
}
struct Parent
{
std::vector<Child> vec;
}
void func(Parent* p)
{
std::vector<Child>& ref = p->vec; // is this ok?
int value = 10;
ref[0].func(value); // is this ok?
}
int main()
{
...
...
Parent p;
func(&p);
...
...
return 0;
}
compiler gcc 4.4.7 (under c++11)
I guess, would it be okay if changed the value of the reference?
ref[0].func(value)
Thank you.
std::vector<Child>& ref = p->vec; // is this ok? yes
int value = 10;
ref->func(value); // is this ok? no
ref is not a pointer so you cannot use the member access operator ->
ref is a vector, so you need to pick which Child you want to use.
ref[ child_index ].func(value);
reference is nothing else but another name of an object. So these are all the same:
std::vector<Child>& ref = p->vec;
std::vector<Child>& vecAlias = ref;
int value = 10;
ref[0].func(value);
vecAlias[0].func(value);
p->vec[0].func(value);
You can't change a value of a reference. Uninitialized referenced don't exist. Once it's initialized there is no way of changing it.
Pointers on the other hand have similar purpose: they allow access to the same data from different places. You can always change what a pointer points to. But pointers are also more error-prone as then can be uninitialized or null-initialized. So try to stick to references if you don't need this flexibility.
Alright, so I have looked around online and clearly my problem is that I'm using a variable "val" here that stops existing when the function closes. Unfortunately, I haven't really found any actual solutions to my problem here. I'm sure this is an easy enough problem to solve once you know how, but I just don't have the knowledge.
In this code, just notice I'm trying to return an unsigned int val. I can't do that because the code wants a reference, not just a variable. I can't simply return val but I don't know what to do.
http://i.imgur.com/E8sf2aS.png
Thanks for the help.
Edit: sorry, I had some problems with the image, apparently I need to work on my rep.
I'm going to take a wild guess.
Foo& doStuff()
{
// blah blah
Foo val;
// ...
return val;
// val is no longer valid end of scope. Returning invalid reference.
}
Either pass in the result Foo instance to doStuff, or create a new Foo on the heap and return as pointer.
So,
void doStuff(Foo& val)
{
// blah blah
// ...
val = x;
}
or
Foo* doStuff()
{
// blah blah
Foo* val = new Foo; // dont forget to delete
// ...
return val;
}
Of course, you can return by value:
Foo doStuff()
{
// blah blah
Foo val;
// ...
return val;
}
Depending on how heavy a Foo is. Of course, since in this case a Foo is just an small int, you should simply return by value. For some cases of return by value for large/non-trivial types, a temporary copy is created (In those instances where there is no copy elision via RVO or NRVO); in these cases you might want to avoid returning large object types by value.
This code has a lot of problems, apart from being given in an image (!!!)
I guess you're trying to find the element at position pos-1 in a list, or something. The main problem referring to your question seems to be that you're first assigning val by value, then you have no reference to return. You should return n2->value directly, which should be a reference to unsigned int, like that:
const unsigned int &list::operator[](unsigned int pos) const
{
node *n1 = ???, *n2 = ???;
for (unsigned int k = 0; k < _size; k++)
{
if (k == pos)
return n2->value;
n1 = n2->next;
n2 = n1;
}
return ???;
}
Other problems remain, e.g.
why you need two node* and not just one (looking for position pos-1 directly)
how to initialize n1, n2 (somehow pointing to the head of your list; obviously new node() should not work)
what to return if input argument pos is out of range (possibly return a reference to some static variable that you can detect, or throw an exception)
For these problems, more context would be needed from your side.
Reference variables, are only valid if the object to which "refer" to, exists in memory. Passing around references to an out of scope variable, is considered undefined behavior.
This is the mistake in your code.Please correct it.
const unsigned int& list::operator[] (unsigned int pos)const
{
const unsigned int val = 0;
return val; //this is a local variable, whose scope ends here, a reference to this should not be returned
}
This is the compiler's warning, to your code.
warning: reference to local variable ‘val’ returned [enabled by default]
Please listen to compiler warnings (especially c/c++ !!), in your case simply using pass by value, would have been sufficient.
Edit:
In case the return variable, is enforced to be a reference type, and cannot be avoided, you can then extend the life of you local variable, to throughout the existence of the program by making it static.
const unsigned int& list::operator[] (unsigned int pos)const
{
static const unsigned int val = 0;
return val;
}
Th variable val is now a static local variable, whose life is throughout the program,
so pasing around references to this variable should be OK, but not recommended programming,
since a pass by value will suffice for the needs of your application.
While trying to find out a problem that occurs only in a release build and not in the debug build I noticed the following behaviour (String would be invalid and would not point to anything while the int would be fine). I have given code below which gives an idea of what I was going through
typedef boost::shared_ptr<MyClass> shared_cls
typedef std::deque<shared_cls> vector_def;
typedef boost::shared_ptr<vector_def> shared_vector_def;
typedef boost::unordered_map<int,shared_vector_def> inner_map_def;
typedef boost::shared_ptr<inner_map_def> shared_inner_map_def;
static boost::unordered_map<std::string,shared_inner_map_def> bcontainer;
shared_cls& SomeMethod(const std::string& symb,const int& no)
{
shared_inner_map_def tshare = bcontainer[symb];
shared_vector_def tmp = tshare->at(no);
shared_cls t = tmp->back();
return t
}
The object MyClass looks like this
class SomeClass
{
private:
int i;
std::string s;
void set_i(int rx)
{
i = rx;
}
int get_i()
{
return i;
}
void set_s(std::string rx)
{
s = rx;
}
std::string get_s()
{
return s;
}
}
Now when I use the above method as in the following code
void main()
{
shared_cls r = SomeMethod("IBM",12);
//Here r does not have a valid string s
//However it does have a valid int i
}
Now my question is in the above main when I call the SomeMethod the r returned does not have a valid string s. It has a scrambled value I found this out by using a logger. However the value of s is totally find during the function SomeMethod. I resolved this issue by not returning the shared pointer by reference.In that case it works. Why does removing the reference make it work
Your shared_cls t goes out of scope because it is defined in the function SomeMethod itself. You need to return shared pointers by value if they are defined in the scope. In the link, it is explained why it is dangerous to return the reference of a temporary object.
In the case of std::string, string has a reference counting mechanism and when it's reference is decremented to zero, it becomes invalidated and a segmentation fault may be observed in such a case. Even if member int i is returned properly, it is still undefined behavior.
I understand the concept of references in C++, and I understand what they do when used in function parameters, but I am still very much confused on how they work with return types.
For example, when used in parameters, this code:
int main (void) {
int foo = 42;
doit(foo);
}
void doit (int& value) {
value = 24;
}
is similar to this code:
int main (void) {
int foo = 42;
doit(&foo);
}
void doit (int* value) {
*value = 24;
}
(knowing that the compiler will automatically put an asterisk in front of value every time it is used in the first code sample of doit, but in the latter you'd have to put the asterisk in yourself every time you try to use value)
So when used as a reference what does this next code (using reference in a return type) translate to? Does it return a pointer to an int? Or would it just return an int?
int main (void) {
int* foo = /*insert useful place in memory*/;
foo = doit(foo);
}
int& doit (int* value) {
//insert useful code
}
It means you return by reference, which is, at least in this case, probably not desired. It basically means the returned value is an alias to whatever you returned from the function. Unless it's a persistent object it's illegal.
For example:
int& foo () {
static int x = 0;
return x;
}
//...
int main()
{
foo() = 2;
cout << foo();
}
would be legal and print out 2, because foo() = 2 modifies the actual value returned by foo.
However:
int& doit () {
int x = 0;
return x;
}
would be illegal (well, accessing the returned value would), because x is destroyed when the method exits, so you'd be left with a dangling reference.
Returning by reference isn't common for free functions, but it is for methods returning members. For example, in the std, the operator [] for common containers return by reference. For example, accessing a vector's elements with [i] returns an actual reference to that element, so v[i] = x actually changes that element.
Also, I hope that "is essentially equal to this code" means that they're semantically sort of (but not really) similar. Nothing more.
It means that you return a pointer to the memory address where the correspondent data is, instead of the very data.
Assuming this code (to make it comparable to the first example) :
int main (void) {
int* foo = /*insert useful place in memory*/;
*foo = doit(foo);
}
int& doit (int* value) {
*value = 24;
return *value;
}
The int& is not really useful as a return type in this case, because it provides access to the variable in memory (of which you pass the pointer to the function).
Does it return a pointer to an int? Or would it just return an int?
No, it returns a reference to an int. If you want, you can look at it as a pointer which can not be nullptr.
Hmm, the best way to know the answer is to have a try...
Your codes will not pass type check, because doit will return a reference of int while you accept the return value as a pointer of int.
You can have a look at this:
#include<iostream>
using namespace std;
int& doit (int* value) {
value[0] = 3;
return value[4];
}
int main (void) {
int* foo = new int[10];
for (int i=0; i<10; i++)
foo[i] = i;
int& bar = doit(foo);
cout<<bar<<endl;
for (int i=0; i<10; i++)
cout<<foo[i]<<" ";
cout<<endl;
bar = 12;
for (int i=0; i<10; i++)
cout<<foo[i]<<" ";
cout<<endl;
return 0;
}
The variable "bar" will accept the return value, and it can be used change the content of "foo". As is mentioned by Luchian, it maybe dangerous to return a reference from the function, because the later codes might modify a value which is in the stack.