I wrote the following code, and I was expecting to get
5
6
6
6, but I got 5 6 5 0 instead. It seems that "val" gets the reference correctly in the beginning, but then it gets lost. Does anybody know where is my mistake?
class Count {
public:
void add() {
val++;
}
void print() {
cout << val << endl;
}
Count(int c): val(c) {
}
private:
int &val;
};
int main() {
int c = 5;
Count teste(c);
teste.print();
teste.add();
teste.print();
cout << c << endl;
teste.print();
return 0;
}
Your constructor should take the parameter by reference, not by value.
The issue here is you are binding a reference to a parameter passed by value. This should be illegal but maybe it isn't. (Does a parameter passed by value have the same status as a temporary and does that apply to primitive types too?)
What compiler is this?
As SpaceCowboy points out if your constructor takes a reference parameter it will work. It should do, it is the normal way to wrap a reference. Of course val will be invalid once c goes out of scope.
You set your private member val as a reference to the local variable c in your constructor. Once you exit the constructor, its a reference to some random value on your stack.
Yes. Either change 'int & val' to 'int val' or change 'Count(int c)' to 'Count(int & c)', that will do the job. by now you're receiving a copy in the c'tor and because you assign that copy to a reference you will get undefined behavior because when the flow gets out of the constructor's scope, the copy will be terminated hence your object will hold a reference to a random place on stack!
Related
I want to write a class with a reference as a field, but am finding that even this simple code which initializes the reference and prints its value fails:
struct Referencer {
explicit Referencer(int in) : num(in) {}
void print() {
std::cout << num << std::endl;
}
int #
};
int main() {
int longlived = 500;
Referencer ref(longlived);
ref.print();
}
The result is garbage (no errors are thrown, nor does the program segfault). My understanding is that the variable longlived has the same lifetime as the instance of Referencer, as they are both declared in the stack and have the same scope. Therefore, the field num should point to valid stack memory when ref.print() is called. Why is this not the case?
The constructor of Referencer takes the argument by value. So in holds a copy of the value in longlived. You then initialized num to a reference to in, which get's destroyed as soon as the constructor returns.
If you want num to hold a reference to the object used as the argument in the constructor, pass in by reference like explicit Referencer(int &in) : num(in) {}.
Hello can anyone help me with this?
I have a class with member by reference:
class name{
int& broj;
string ulica;
And have constructor:
public:
kuca(int b, string s) :broj(b)
{
ulica = s;
}
and info class for output
void info(){
cout << broj << ulica << endl;
}
};
When i create object and try to output it
int isbn = 1;
name a(isbn, "text");
a.info();
for reference value i am getting junk/random value it seems, while other attribute is written fine:
-858993460 text
A reference member always has the danger of becoming dangling: when the original object to which the reference refers goes out of scope. In your case, this happened instantly (as the object was a temporary), but even if you follow the suggestion
kuca(int&b, const string&s) : broj(b), ulica(s) {}
^^^^^
you can easily get into trouble. For example
kuca make_kuca()
{
int x=7;
return {x,"bad"};
}
auto k=make_kuca();
when the returned object's reference member refers to a variable (x) that has just gone out of scope.
Therefore, reference data members should be used with care to ensure that their lifetime never exceeds that of they variable they refer to.
You have to write at least
kuca( int &b, string s) :broj(b)
^^^^^^
{
ulica = s;
}
Otherwise variable b is a local variable/object of the constructor that will be destroyed after executing the constructor and the reference will be invalid.
change your ctor signature as follows:
kuca(int& b, string s) :broj(b)
note the int& instead of int. Then, the parameter b will refer to the variable isbn rather than to some call stack location.
It should be noted that with the original signature
kuca(int b, string s) : broj(b)
you're taking a reference of the parameter that's a copy passed on the stack. So, when the info() method is called, then broj refers to a location on the call stack rather than to the variable isbn. That is why it appears to print a "random" value.
You're storing a reference to the parameter b, which exists only during the constructor call. After the constructor call you're left with referencing an int that doesn't exist.
As everyone already said, you probably meant this...
kuca(int b, string s) :broj(b)
to be
kuca(int& b, string s) :broj(b)
There isn't any performance benefit to passing an int by reference though, and the reference is invalid as soon as the int goes out of scope which could create a difficult bug to track down.
My personal preference is to pass by address whenever the variable can be mutated.
class name {
public:
kuca(int* b, string s) : broj(b), ulica(s);
private:
int* broj;
string ulica;
}
That turns the above into a compile time error. Using a reference as a class member is easy to use incorrectly.
I have always assumed that passing variables with [pass-by-value] in [c++], makes a copy of them, and so the function receiving these copies can not change the original variable's content.
I guess it is because when argument is passed by value, [copy-constructor] is called, and if it is not overridden by the programmer, the default [copy-constructor] does [shallow-copy] instead of [deep-copy]!
So my question is that why they called it pass-by-value, while in the case of having pointers in the class, the function has access to the reference of that pointer and can damage it. Also is this conclusion correct? "Whenever have pointers in the class, and you might pass an object of that class by value as a function argument, define the copy constructor!"
If this error is famous, does anyone know the name or phrase to this problem?
Below is my code that resulted in a modified list. Objects of this class contain an int member variable
as well as a pointer to a list of nodes member variable.
class ComplicatedObject{
public:
ComplicatedObject();
~ComplicatedObject();
//ComplicatedObject(const ComplicatedObject& c); // copy construtor
//ComplicatedObject& operator=(const ComplicatedObject& c); // =operator
int int_member_varialbe_; // an int member variable
void addToList(int d);
void printList();
private:
struct node{
int data;
node* next;
};
node* head_; // points to the beginning of a list (linkedlist of int)
};
The below code prints 2. And then prints 2 3 !
Test.cpp:
void myfunction(ComplicatedObject obj){
obj.addToList(3);
obj.int_member_variable_ = 5;
}
int main(void){
ComplicatedObject c_object;
c_object.addToList(2);
c_object.printList(); //prints 2
cout << "int member variable befor passing:";
cout << c-object.int_member_variable_ << endl; //prints 6 (a default value)
myfunction(c_object); //pass-by-value
cout << "int member variable after passing:";
cout << c-object.int_member_variable_ << endl; // prints 6 (not 5)
c_object.printList(); // prints 2 3 ! List get changed!
return 0;
}
You are correct. A shallow copy (which occurs if your class lacks a copy constructor) copies the pointers in your class, but not what they point to. You must define a copy constructor which performs a deep copy if you'd like to be able to properly pass a non-const object by value.
I have always assumed that passing variables with [pass-by-value] in
[c++], makes a copy of them, and so the function receiving these
copies can not change the original variable's content.
Yes, that's true.
I guess it is because when argument is passed by value,
[copy-constructor] is called, and if it is not overridden by the
programmer, the default [copy-constructor] does [shallow-copy] instead
of [deep-copy]!
A "copy" is a "shallow copy". A "copy" copies all the contents of the objects. And the contents are the fields. And if the field is a pointer, then the content is the pointer, the address. That's it.
So my question is that why they called it pass-by-value, while in the
case of having pointers in the class, the function has access to the
reference of that pointer and can damage it.
So? The things that those pointers point to are not part of the object. So it's irrelevant. The pointer is what's part of the object.
So my question is that why they called it pass-by-value, while in the case of having pointers in the class, the function has access to the reference of that pointer and can damage it.
Let's consider the following situation:
int func(int b, int* c)
{
/* some stuff */
}
for the first parameter, b, it is a "ByVal" delivery, so what the compiler usually does is
Create sizeof(int) space for b
Copy b to the space
The func can modify the local copy of b without affecting original b
This is necessary, since if it is automatically delivered "ByRef", compiler will meet trouble when non L-value is given, i.e. 1, as you cannot get the reference from a constant value.
Now let's see what happens to c. Again, it has a type of int*, not a int&, so it is treated the same way like int b.
However when c is a int* pointer, it does not store any other data except the address to some object with type int. So indirect access via the pointer is permitted and there is only copy of the address but not the value it points to,thus can be damaged.
Assuming I have:
class A which is non-copyable
class B which has as a member, const A& a (and takes an A in its constructer and sets it in its initialization list)
a function A GenerateA();
Does this mean that it should be valid to do:
B(GenerateA())
?
i.e, does the const ref mean that no copy of the A that generateA() returns is done? And does that mean that the scope of the returned temporary is extended for as long as B exists?
EDIT: Addon question from the comments:
Is it acceptable to return a A& from GenerateA() to a local A, if the lvalue is a const A&?
Thanks!
If A is non-copyable, then the function A GenerateA() is invalid since returning by value requires creating a copy.
If the function returns a reference instead (i.e. A &GenerateA()) and the reference is to a locally created A object, it becomes invalid as soon as the function exits. C++ doesn't have any form of garbage collection, so there is no way to "extend" the lifetime of an object as long as it is in use.
As it has already been stated by others, A GenerateA() cannot compile if A is not copyable.
Regarding the const ref : no, the lifetime of the temporary will not be extended to the lifetime of B. The standard [12.2.5] states :
A temporary bound to a reference member in a constructor's ctor-initializer (12.6.2) persists until the constructor exits. [...] A temporary bound to the returned value in a function return statement (6.6.3) persists until the function exits.
So yes, extension of the lifetime of a temporary exists in some contexts (and is sometime truly useful : see this article), but not in the one you presented.
Regarding your last question, it's not legal to return a reference to a local variable from GenerateA() (and binding the result to a const reference won't be of any help).
Yes and No.
Yes, the const reference will bind to the temporary variable. No, const references which are class members do not extend lifetime the way const references with automatic duration do.
Here's an example:
#include <iostream>
using namespace std;
int& GenX(bool reset)
{
static int* x = new int;
*x = 100;
if (reset)
{
delete x;
x = new int;
*x = 200;
}
return *x;
}
class YStore
{
public:
YStore(int& x);
int& getX() { return my_x; }
private:
int& my_x;
};
YStore::YStore(int& x)
: my_x(x)
{
}
int main()
{
YStore Y(GenX(false));
cout << "X: " << Y.getX() << endl;
GenX(true); // side-effect in Y
cout << "X: " << Y.getX() << endl;
return 0;
}
Output:
X: 100
X: 200
class Sample
{
public:
int *ptr;
Sample(int i)
{
ptr = new int(i);
}
~Sample()
{
delete ptr;
}
void PrintVal()
{
cout << "The value is " << *ptr;
}
};
void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}
int main()
{
Sample s1 = new Sample(10);
SomeFunc(s1);
s1.PrintVal();
}
Two things that I think should happen:
s1 can be initialized using the parameterised constructor.
The value of *ptr from PrintVal() should be 10.
For 1) I'm getting invalid conversion from 'Sample*' to 'int' [-fpermissive]. I'm calling the constructor properly, why is this happening?
For the case of 2) I'm getting either a garbage value or the program gets an segmentation fault. This shouldn't happen because the ptr of the local object x of the SomeFunc should be deleted not the ptr of s1 as it is passed by value not reference. IIRC pass by value for objects sends a copy of the object to the function's receiving arguments.
Your code does have undefined behaviour. But let’s start at the beginning.
Sample s1 = new Sample(10);
This is what happens in this line:
A Sample object is allocated on the heap and the new expression returns a pointer to it, a Sample*.
You cannot assign a Sample* to a variable of type Sample. But Sample has a constructor that allows implicit construction from an int. If you use the -fpermissive compiler option (hint: don’t!), the compiler allows implicit conversion of a pointer to an integer – after all, a pointer is just a memory address, a.k.a. a number.
Accordingly s1 is constructed by interpreting the memory address of the heap Sample object as an integer (truncating it if sizeof(Sample*) > sizeof(int)). That’s the value that ends up as *(s1.ptr).
To reiterate the key point: In that line you don’t instantiate one Sample object, but two. Bug 1: The one created on the heap is never deleted. That’s a memory leak.
SomeFunc(s1);
Sample has nothing in it that prevents the compiler from generating the default copy constructor and default copy assignment operator. Important: “default” for pointers means to copy the pointer, not the object behind it. So:
s1 is copied to call SomeFunc(). The copy is available as x in the function. Because of the default pointer copy both s1 and x point to the same int object.
x goes out of scope at the end of the function, the destructor runs and deletes the int object.
We are not quite undefined yet, but we’re getting close.
s1.PrintVal();
The function tries to acces the int object behind the pointer, but it’s already deleted. s1.ptr is a dangling pointer. Bug 2: Dereferencing a dangling pointer is undefined behaviour.
And all that because of that seemingly innocent implicit pointer-to-int conversion … That’s why it is a compiler error by default, at least in non-ancient compilers.