Sometimes when I'm programming in C++ I wish there was an undefined value for every variable something like Javascript!.
For example when I'm returning a value for out-of-bounds element of an array, it was useful to return an undefined instead of throwing an exception, or:
template <typename T, int SIZE>
class MyArray
{
T arr[SIZE];
static T badref;
public:
T &operator[](int i)
{
if (i >=0 && i < SIZE)
return arr[i];
else
throw std::string("OUT-OF-BOUNDS"); // or: return badref; !!
}
};
Another dirty(In my opinion) option is returning a reference of a pre-defind variable as a bad-reference variable. I know we can not assign null or something like that to a reference variable.
Is there an another well formed pattern to return a reference where caller has the ability to find out the returned value is not valid?
EDIT: I'm not mean a pointer
You can use boost::optional as #chris mentioned in his comment. It comes as a part of Boost libary. See this page for more details.
Modified MyArray class:
template <typename T, int SIZE>
class MyArray
{
T arr[SIZE];
public:
optional<T&> operator[](int i)
{
if (i >=0 && i < SIZE)
return optional<T&>(arr[i]);
else
return optional<T&>();
}
};
Usage:
MyArray<int>() array;
// fill array with data
optional<int&> result = array[0];
if (result) {
// item was found
} else {
// index out of bounds
}
I wish there was an undefined value for every variable something like Javascript!
You only have an "undefined" value for pointers (nullptr). A reference is (by definition) something pointing to a valid instance.
To return a reference to a static object, you should separate between const and non-const values of your operator:
template <typename T, int SIZE>
class MyArray
{
T arr[SIZE];
static T badref;
public:
T &operator[](int i)
{
if (i >=0 && i < SIZE)
return arr[i];
else
// returning ref here would allow clients to write:
// MyArray<int> a;
// a[-1] = 5; // valid if you return a non-const reference
throw std::string("OUT-OF-BOUNDS");
}
const T &operator[](int i) const
{
if (i >=0 && i < SIZE)
return arr[i];
else {
// MyArray<int> a;
// a[-1] = 5; // will not compile (cannot assign to const)
static const T invalid = T();
return invalid;
}
}
};
Whatever you think of, your solution needs to fit into the type system. So your function signature must explicitly say (this way or another) that the result may be T, but it may be something else too.
Common ways for that are:
Instead of returning a value, return a status code and output the value via an "out" parameter (a pointer or reference):
bool tryGet(int i, T& result);
Return a tuple (status, value) like:
std::tuple<bool, T> get(int i)
(If couldn't get, consider the second tuple element irrelevant - requires T to have a default constructor)
Use boost::variant (flexible, but requires boost)
Use boost::optional (simpler version of the above, when you only need "either T or nothing")
The main goal of references is to avoid invalid (NULL) values while allowing functions to modify their arguments and keep from copying data. If you need a NULL value, use a pointer.
Related
Please consider this scenario.
I'm creating a function for [] operator as in the std::vector whose inner body is like this:
int temp;
if(argument >= 0 && argument < size) {
return &my_vector[i];
} else {
cout << "out of bounds" << endl;
//i need to return here something but this gives me an error: local variable cannot be returned by reference.
return &temp;
}
where argument is the argument passed to the function. The return type for this function is 'T*'.
I'm looking for both the read and write cases:
vector[100] = 1;
and int answer = vector[100];
That's why they are returned by reference.
What should be returned in the else part?
First of all, you are not returning a reference, but a pointer, which makes the method not very useful. Instead of
vector[100] = 1;
int answer = vector[100];
You would have to write
*vector[100] = 1;
int answer = *vector[100];
To get what you want you should return a reference not a pointer. Ie return type should be T& not T*.
Then you have basically two options. Either you mimic vectors operator[]. It does not do any bounds checking. It is up to the caller to make sure to pass valid indices:
return my_vector[i]; // thats all (assuming my_vector[i] returns a reference)
The other option is to throw an exception as std::vector::at does:
if(i >= 0 && i< size) {
return my_vector[i];
} else {
throw std::out_of_range("invalid index");
}
You cannot return a reference to a local variable, because that reference is dangling as soon as the method returns and the local variables lifetime ended.
You have to choose which approach fits better. std::vector offers both. Typically when the method is called in a loop:
for (size_t i=0; i<size;++i) {
foo[i] = i;
}
You do not want to incur the overhead of checking the index on each access. On the other hand sometimes indices are computed and the caller wants to have the bounds check encapsulated rather than doing it manually:
try {
size_t index = some_function(); // is this a valid index?!?
foo.at(i) = 42; // let at check it
} catch(...) {
//...
}
PS: You typically need two overloads for those accessors, one const and one non-const, returning const T& and T&, respectively.
I want to return a boolean or success/failure enum from the function and modify an argument by reference. However, I want to construct a reference in the calling function instead of copying the value.
I have some container (say 'example_q' of type std::queue). queue.front() will return a reference to the value stored in the queue. I can make a copy of that reference (example A) or I can take a reference of that reference (example B), allowing the value to stay in the queue but be utilized outside of it.
A)
int a = example_q.front();
B)
int& b = example_q.front();
Using this difference I could also return the queued value:
A)
int get_front()
{
int a = example_q.front();
return a;
}
B)
int& get_front()
{
return example_q.front();
}
Using option 'B' I can avoid unnecessary copies without moving the data out of the queue via std::move() semantics.
My question is, can I do 'B' via an argument passed by reference? Would I need to use std::move()/rvalues/&& somehow?
void get_front(int& int_ref)
{
// somehow don't copy the value into referenced int_ref, but construct
// a reference in the caller based on an input argument?
int_ref = example_q.front();
}
The problem this would solve is making API match other functions that modify reference arguments but return a success/failure value, ie:
if(q.get_front(referrence_magic_here))
{
...
}
I could reverse the order to get the desired result, IE:
int& get_front(bool& success)
{
...
}
But I'd rather keep the pattern of my API as well as being able to do it via a single line in the if() statement if possible.
Perhaps something like:
bool get_front(int&& int_rvalue)
{
...
int_rvalue = example_q.front();
...
return true_or_false;
}
void calling_func()
{
...
if(get_front(int& magical_ref))
{
... //use magical_ref here?
}
...
}
No, you can't do that.
Other than in its initialiser, a reference behaves like the thing it refers to. By passing it as a function argument, you "hide" the initialiser from the part that wants to do the assignment. So, the function has no access to the referencey behaviour of the thing.
You will have to use pointers if you want to do that:
void get_front(int*& int_ptr)
{
int_ptr = &example_q.front();
}
int* ptr = nullptr;
get_front(ptr);
// optional:
int& ref = *ptr;
(Ew!)
Option B was fine.
This code is invalid C++:
if(get_front(int& magical_ref))
You cannot declare a new variable as you're passing it to a function. And because a reference variable must be declared and initialized at the same time, it wouldn't be possible to have a reference be initialized by passing it to a function.
You could however, do this:
if(int &magical_ref = get_front()) {
But note that you'd be checking whether magical_ref is 0 or not, which is different from the condition you have in your example.
If your logic is as simple as comparing the int, you could do:
if (int& magical_ref = get_front(); magical_ref == 42)
You can return a std::tuple<int&, /* status condition */> and check the status. For example:
std::tuple<int&, bool> get_front() {
static int example = 0;
return {example, false};
}
...
// C++17's structured bindings + if statement with initializer
if (auto [ref, success] = get_front(); success) {
ref = 42;
}
Demo
I want to define s[i] to return 0 if s[0] was never assigned and return a reference to s[i] if s[i] was assigned earlier (to implement a sparse array). The following code does it, but it ends up creating s[i] whenever I try to get its value, because of the semantics of map.
struct svec{
map<int,double> vals;
/*
double operator[](int index){
return (vals.count(index) > 0) ? vals[index] : 0 ;
else return 0;
}
*/
double &operator[](int index){
return vals[index];
}
};
int main(){
svec s;
s[0] = 10;
cout << s[1] << endl;
}
I want the commented code to be used for resolving the expression s[1]. But if I uncomment it, I get an error.
You cannot overload return values, so you'll have to stick with either returning by reference or by value (or by pointer, etc). The problem with returning by reference is that you have to refer to an existing value that lives in memory. This is, of course, fine when the value is in the map. When it's not, you have to create the default value and store it in memory. Then you have to make sure to properly delete it to not leak memory, but also to make sure the user isn't holding references to the values, as it would introduce unexpected behaviour.
Also, you have to consider the fact that the user can change the value you're returning. If you return the same default, then it's possible for the user to change it to another value. Then all subsequent calls would return a reference to the new value. Resetting the default to 0 every time you return it would also be unexpected for all users that are still keeping a reference to it.
You probably could solve this problem in a stable way, but it would probably require much boilerplate code. I would suggest putting the burden on the user in this case.
class SparseVector {
private:
std::unordered_map<int, double> elements;
public:
void set(int index, double value) {
elements[index] = value;
}
double& get(int index, double& optional) {
auto it = elements.find(index);
if (it != elements.end())
return it->second;
else
return optional;
}
double& get(int index) {
auto it = elements.find(index);
if (it != elements.end())
return it->second;
throw std::runtime_error(
"Couldn't find element at index " + std::to_string(index) +
"! Use get(int index, double& optional) if you don't want errors."
);
}
}
int main() {
double default_value = 0.0;
SparseVector vector;
std::cout << vector.get(0, default_value) << std::endl;
}
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.
I have done numerous searches and found a ton of examples and tutorials but still cannot figure out how to get the value when writing to the [] operator...
I feel like i'm going insane. I must be missing something very simple
as far as i can tell there is a single function for get and set and it looks something like this:
V& operator[](string K);
or this:
double &operator[](int n);
now great, we can get what is:
a[HERE]
as HERE becomes double &operator[](int HERE);
and we can easily work with it
but how do we get what is:
a[4] = HERE
C# has two very clear get and set methods with the value keyword which represents the object being assigned.
public string this[int key]
{
get
{
if(key == 1)
return "1!";
if(key == 2)
return "2!";
else
return "3!";
}
set
{
if( value == "setting") //value is a[3] = THIS
this.isSet = true;
}
}
Don't think of operator[] as a function to get or set, that might be confusing. Think of it as a normal function. In fact, let's re-write it as a normal function:
struct X
{
int arr[10];
int& getIndex(int idx) { return arr[idx]; }
};
//...
//initialize x of type X
x.getIndex(3) = 42;
The method x.getIndex(3) will return a reference to the 4-th element in the member array idx. Because you return by reference, the return value is an l-value and refers to that exact element, so you can assign a value to it, say, 42. This will modify the member x.arr[3] as the function returns an alias for that particular object.
Now you can re-write this in terms of operator[] exactly as before
struct X
{
int arr[10];
int& operator[](int idx) { return arr[idx]; }
};
and get the same result by calling
x[3];
or even
x.operator[](3);
The operator option is just syntactic sugar.