i'm trying to pass an vector by reference, which gets modified inside the function (lets say, something like sorting the vector)
void dummy(vector<int> &v) { sort(v.begin(), v.end()); }
The above works only when creating the vector like this and passing the reference, which is expected.
int main() {
vector<int> v = {1, 2, 3};
dummy(v);
}
I'm trying to figure out, if there is an inline way of doing this ? Usually, if the vector is not getting modified we can do something like this -
int main() {
dummy({1,2,3})
}
But, when the vector gets modified, it throws an compilation error saying - cannot bind non-const lvalue reference of type 'std::vector&' to an rvalue of type 'std::vector. So, is there a way to send the vector's reference inline?
In that case you should write an overload for an rvalue reference, namely:
void dummy(vector<int>&&);
This will work with the temporary object passed to the function.
If the vector is not getting modified, you can use const to reference:
void dummy(const vector<int> &v) { .. }
dummy(vector<int>{1, 2, 3});
You can also use universal references &&:
void dummy(vector<int> &&v) { .. }
To elaborate on masoud's answer, if you are passing an outside vector into a function that accepts is as a universal reference you may need to use std::move to avoid a compiler error or implicit duplication of the object. It's best practice to explicitly use std::move when passing something that is not already an explicit universal reference.
The compiler error is intended to avoid a mistake by the developer (accessing the object after its ownership has moved which may have undefined or unexpected behavior depending on the object type). So std::move implies your intention to forfeit outside ownership of the object in question. And depending on what class you are using, it may duplicate the object before passing it in as a universal reference, so std::move would prevent that unintended possibility as well.
void dummy(vector<int> &&v) { ... }
vector<int> myVector = {1, 2, 3};
dummy(std::move(myVector));
Related
I am calling a function with the signature
void setValue(int& data)
I would like to pass a literal number to it:
setValue(1);
But I get:
error: invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
Is there a way I can make this work without changing the function (it's in a library) and without assigning each literal value to a variable?
Assuming setValue does not actually modify its argument and just has a wrong signature which you cannot change, here is an approach which is not thread-safe among other things:
#include <iostream>
void setValue(int &i)
{
std::cout << "i = " << i << std::endl;
}
int& evil(int i)
{
static int j;
j = i;
return j;
}
int main()
{
setValue(evil(1));
setValue(evil(2));
}
When you declare the argument as being an int&, you are saying that the function called can change the value and the caller will see the change.
So it is no longer valid to pass a literal value then because how could the function possibly change the given value of a literal?
If you don't want the setValue to be able to change the given value, make the argument either be an int or const int&. And if you do want the setValue function to be able to change the value, then the caller must declare a non-const variable to hold the int and pass in that.
Can I change something at the call site to make it work
The problem with your code is that you declared your function to expect a reference, which means the compiler has to prepare the code to allow the function to change whatever you pass into it at the call site. So yes, sure, you can declare a variable, set it to 1 and call your function with it.
Contrast this with a constant reference in the declaration, where the compiler knows you won't change it inside the function, and then you can pass a literal in without issues. In fact, any logical, thought out design will make setters accept constant parameters because it won't change them, it will just store a possibly processed value in its state.
The answer to „what do I do if a library has a bad interface and I can't change it“ is usually „write a wrapper“. Assuming this is a method of some class BadLibraryClass, you could do something like:
class Wrapper {
public:
BadLibraryClass inner;
setValue(int i) {
inner.setValue(i); // i is an lvalue
}
};
This is just a crude example. Perhaps inner is better off being a pointer, a reference or even a smart pointer. Perhaps you want a conversion operator to BadLibraryClass. Perhaps you can use inheritance to expose other methods of BadLibraryClass.
Two options:
Use the result of assignment:
static int _data;
void myCall() {
setValue((_data = 3));
}
Write a wrapper:
struct setValueW {
int _data;
// constructor
setValueW(int _data) : _data(_data) {
setValue(_data);
}
// if you want to call it again
void operator()() {
setValue(_data);
}
};
void myCall2() {
setValueW(3);
}
AFAIK, references keeps the addresses of the variable. 1 is not variable. It is temporary.
Take a look this article(this is a quote from this site)
c++11 introduced a new kind of reference variable -- an r-value reference
To declare one, use && after a type
int & // type designation for an L-value reference
int && // type designation for an R-value reference
L-value references can only refer to L-values
R-value references can reference to R-values (temporaries)
int x, y, z; // regular variables
int & r = x; // L-value reference to the variable x
int & r2 = x + y; // This would be ILLEGAL, since x + y is an R-value
int && r3 = x + y; // LEGAL. R-value reference, referring to R-value
So you can use (But this is not useful. It may be more useful if you write this in plain without rvalue or lvalue.):
void setValue(int&& data)
setValue(1);
Or you can use that:
void setValue(int& data)
int a = 11;
setValue(a);
Don't forget for second example. If you change the value of data parameter. You will have change the a variable value.
No, you can't.
An lvalue reference like that binds to a variable (roughly speaking).
Your literal is not such a thing. It never had a name, and may not even have a home in memory.
Your two options are the two things you ruled out, I'm afraid.
For what it's worth, this is not your fault: that is a rather poor setter. It should take const int& (which will automatically create a nice temporary variable for you out of the literal!), or even just const int.
I'm confused between the subtle differences of passing vectors
This is some part of my program
void print(vector<vector<char>>&field)
vector<vector<char>> bomb(vector<vector<char>>&field)
I encountered a case where I can't do something like this
print((bomb(bomb(field)));
The error is
error: invalid initialization of non-const reference of type 'std::vector<std::vector<char> >&' from an rvalue of type 'std::vector<std::vector<char> >'
print(bomb(bomb(field)));
But if I add a const to the method definition to
void print(const vector<vector<char>>&field)
vector<vector<char>> bomb(const vector<vector<char>>&field)
Then this will work
What is the difference between
1. vector<vector<char>> bomb(vector<vector<char>>&field)
3. vector<vector<char>> bomb(const vector<vector<char>>&field)
4. vector<vector<char>> bomb(const vector<vector<char>>field)
I believe 1 is passing a vector by reference, which is what I've been doing before. How come I can't do something like bomb(bomb(field)) without the compiler complaining?
The return value of bomb is an object, not a reference. The return value is a temporary object. Hence, you cannot use it when the expected type is a non-const reference.
Analogy with simpler objects:
int foo(int& i) { return i+2; }
void bar(int& i) {}
// Can't use
int i = 10;
bar(foo(i));
That is a problem since foo returns a temporary object. Its return value cannot be used as an argument to bar since bar expects a non-const reference.
If the return value of bomb can be changed to a reference,
vector<vector<char>>& bomb(const vector<vector<char>>&field);
without breaking how it works, then you can use:
print((bomb(bomb(field)));
Temporary objects are sometimes created in C++. One example from the STL valarray class would be the slice_array, which is invoked every time a series of indices of a valarray is selected.
http://www.cplusplus.com/reference/valarray/slice_array/
My question is this:
When passing these temporary objects as arguments to a function, is a copy of these objects passed, or only a reference?
E.g. imagine these two naive functions:
double simple_product(double* inp,int length){
double res=1;
for(int i=0;i<length;++i){
res = res*inp[i];
}
return(res);
}
double sum_selected(valarray<double> v){
simple_product(&v[0],v.size());
return(v.sum());
}
If I call them in the following fashion:
valarray<double> valery(10,10);
size_t sel[] = {1,3,4};
valarray<size_t> selection (sel,3);
cout << sum_selected(valery[selection]);
will a new object with a size of 3*size_t be temporarily created within the stack of the function sum_selected or not?
Please note that declaring the function as: double sum_selected(valarray<double> & v)
is not permitted (temporary objects can only be bound to const references).
The reason why this is interesting is that, for example here, it is not possible to declare the function as:
double sum_selected(const valarray<double> & v), because then the function simple_product (which is to be assumed unalterable) cannot be called. However, making a temporary copy of the passed argument would be problematic for memory in case of big arrays.
If the function is declared to take its argument by value, then it's passed by value, creating a new copy of the object:
void f(thing t); // pass by value
If it's declared to take its argument by reference, then it's passed by reference. But it can only take a temporary by const or rvalue reference:
void f(thing const & t); // OK: const lvalue reference
void f(thing && t); // OK: rvalue reference
void f(thing & t); // Error: lvalue reference can't bind to temporary
Passing by reference doesn't create a new object, and the lifetime of the temporary is such that it's valid during the function call, until the end of the statement that creates it.
valarray<T>::operator[](valarray<size_t> const&) returns an indirect_array<T> (reference), or a valarray<T> for the const-qualified operator, not a slice_array.
If you want to be able to access the selected elements as a contiguous array, then you'll need to collect them into a contiguous array. The converting constructor valarray<T>::valarray(indirect_array<T> const&) does this for you. Reference semantics would be useless in this case, as there is no existing object that has your desired elements arranged contiguously.
Changing the function signature to double sum_selected(valarray<double> const&) would make no difference to your code, as a temporary valarray<double> is constructed anyway. It would be more efficient in the case where valery is passed directly, without subscripting.
I would like to create a custom container Container that stores data in individual arrays. However, to facilitate easy iterations over the container, I provide a 'view' on the container by overloading operator[] and return a single struct Value that holds all container variables as references to the actual container. This is what I got so far:
#include <iostream>
using namespace std;
struct Value {
Value(int& data) : data_(data) { }
int& data() { return data_; }
int& data_;
};
struct Container {
Value makeValue(int i) { return Value(data_[i]); } // EDIT 1
Value&& operator[](int i) {
// return std::forward<Value>(Value(data_[i]));
return std::forward<Value>(makeValue(i)); // EDIT 1
}
int data_[5] = {1, 2, 3, 4, 5};
};
int main(int, char**)
{
// Create and output temporary
Container c;
cout << c[2].data() << endl; // Output: 3 - OK!
// Create, modify and output copy
Value v = c[2];
cout << v.data() << endl; // Output: 3 - OK!
v.data() = 8;
cout << v.data() << endl; // Output: 8 - OK!
// Create and output reference
Value&& vv = c[2];
cout << vv.data() << endl; // Output: 8 - OK, but weird:
// shouldn't this be a dangling reference?
cout << vv.data() << endl; // Output: 468319288 - Bad, but that's expected...
}
The code above is working as far as I can tell, but I'm wondering if I use the best approach here:
Is it correct to return the Value as an rvalue reference if I want to avoid unnecessary copying?
Is the use of std::forward correct? Should I use std::move (both will work in this example) or something else?
The output of the compiled program is stated in the comments. Is there any way I can avoid the dangling reference when I declare Value&& vv... (or even forbid it syntactically)?
EDIT 1
I made a small change to the source code so that the Value instance is not directly created in the operator[] method but in another helper function. Would that change anything? Should I use the makeValue(int i) method as shown or do I need to use std::move/std::forward in here?
Is it correct to return the Value as an rvalue reference if I want to avoid unnecessary copying?
No. Returning rvalue references from something that isn't a helper like std::move or std::forward is flat-out wrong. Rvalue references are still references. Returning a reference to a temporary or a local variable has always been wrong and it still is wrong. These are the same C++ rules of old.
Is the use of std::forward correct? Should I use std::move (both will work in this example) or something else?
The answer to the previous question kinda makes this one moot.
The output of the compiled program is stated in the comments. Is there any way I can avoid the dangling reference when I declare Value&& vv... (or even forbid it syntactically)?
It's not the Value&& vv = c[2]; part that creates a dangling reference. It's operator[] itself: see answer to the first question.
Rvalue references change pretty much nothing in this case. Just do things as you would have always done:
Value operator[](int i) {
return Value(data_[i]);
}
Any compiler worth using will optimise this into a direct initialisation of the return value without any copies or moves or anything. With dumb/worthless/weird/experimental compilers it will at worst involve a move (but why would anyone use such a thing for serious stuff?).
So, the line Value v = c[2]; will initialise v directly. The line Value&& vv = c[2]; will initialise a temporary and bind it to the rvalue reference variable. These have the same property as const& used to, and they extend the lifetime of the temporary to the lifetime of the reference, so it wouldn't be dangling.
In sum, the same old C++ of always still works, and still gives results that are both correct and performant. Do not forget it.
Returning a reference to a temporary objects, even if it is an r-value reference, is always wrong! By the time you access the object it will be gone. In that case it also doesn't do what you want it to do, anyway: if you want to avoid unnecessary copies, have one return statement returning a temporary! Copy/move elision will take care of the object not being copied:
Value operator[](int i) {
return Value(data_[i]);
}
Passing the temporary object through a function will inhibit copy/move elision and not copying/moving is even less work than moving.
If I have a function that returns some object like
std::vector<int> foo()
{
std::vector<int> v;
v.push_back(1);
return v;
}
then what's the difference between saying
std::vector<int> &&v = foo();
and
std::vector<int> v = foo();
?
(Why) would I prefer either over the other?
(I suspect this might be a duplicate question, but I couldn't find the right search terms.)
Reading one of these (and thus knowing that it's doing something reasonable) requires understanding about temporaries and how binding a temporary to a reference extends the lifetime of the temporary. The other is:
std::vector<int> v = foo();
Always pick the one that's easier to understand. It also works just as well if foo returned a const& or a &&, whereas storing it by && would only work if it returns by value or by &&.