How to tell if Im using by reference correctly? - c++

So I have a function which sets a variable in a vector and returns a modifiable cell reference back. But I'm unsure if I am using the reference '&' correctly as I have two examples that work.
Ex1:
Cell& Grid::set(const int x, const int y, const Cell & value) {
int index = get_index(x, y);
this->grid[index] = value;
return this->grid[index];
}
Ex2:
Cell& Grid::set(const int x, const int y, const Cell value) {
int index = get_index(x, y);
this->grid[index] = value;
return this->grid[index];
}
Which would be the correct way and how can I tell for the future?
Edit: Cell is an enum not an object

This is a sink function for the value parameter, because of this:
grid[index] = value;
So in this case, you should be passing by non-const value and move it into grid:
Cell& Grid::set(const int x, const int y, Cell value)
{
grid[get_index(x, y)] = std::move(value);
return grid[index];
}
You should make sure that Cell is a movable type though, because if it isn't, it will cost you an extra copy.
This is the common pattern that is used when it comes to sink functions. (Meaning functions that store arguments somewhere that outlives the function call itself.)
Also take a look at another relevant answer to a different question on when it's beneficial to pass by reference.

Related

Where a const reference refers to? [duplicate]

This question already has answers here:
return const reference vs temporary object
(3 answers)
Closed 10 months ago.
There is a simple program
#include <stdio.h>
int counter = 3;
const int& f() {
return counter++;
}
const int& g() {
return counter++;
}
const int& h(int w) {
counter = w;
return counter;
}
void main()
{
const int& x = f();
const int& y = g();
const int& z = g();
const int& t = h(123);
counter = 45678;
printf("%d %d %d %d", x, y, z, t);
}
Why its output is 5 5 5 45678? Especially, why x and y are 5? If they are still connected to the counter after initialization, why they are not 45679 or something like?
Because of post-incrementation that f and g do.
const int& f() {
return counter++;
}
const int& g() {
return counter++;
}
counter++ doesn't actually return the counter, but a temporary int object returned by operator++(int).
In C++, opreator++ has two forms.
Type& operator++(); //pre-increment
Type operator++(int); //post-increment
The int argument in the 2nd version is a dummy used to distinguish the calls, as you can't overload on return type alone
As you can see the post-increment returns by value, not reference, so you're returning a reference to a temporary variable!
You can see warning from GCC and Clang if you turn them on.
https://godbolt.org/z/f1fMP463a
So overall you invoke UB as the references you return are dangling. You ran into the worst case where it just seems to work.
Also, main must return int in C++.
Your program has undefined behaviour. The return values of f and g cease to exist at the end of the statements that call them, so x, y and z don't refer to anything after their declaration.
Just as an addition to the answers given so far: Why undefined behaviour?
Let's consider a hypothetical implementation of operator++:
template <typename T>
T& operator++(T& t) // pre-increment:
{
t = t + 1;
return t;
}
// should be clear so far...
template <typename T>
T operator++(T& t, int) // post-increment:
{
// t = t + 1; // cannot do now, how to return the old value then???
T b = t; // need to store the value in a backup copy first!
t = t + 1; // NOW we can
return t; // need to return the OLD value -> cannot return by reference either,
// it's a TEMPORARY ...
}
As you now use operator++, which itself returns a temporary, you return a reference to temporary that doesn't exist any more after after returning – undefined behaviour.
Why do you now see 5? Pure technically (still UB!): As f and g look identical they both use identical offsets to the stack's end on being called and as being called immediately one after another they both start at the same stack end – so they will store the temporary at the same stack address, which is where the reference gets bound to. Note that this finally contains the value before last increment, thus 5, not 6. h does not need any additional values on the stack, thus the value there won't get overwritten – just alike when doing the assignment, so the value is yet retained. You might have seen something totally different if for some reason h did use the stack itself...

Assigning value to returned shared_ptr doesn't behave as expected

I have a private three dimensional vector of shared_ptr<Room> objects as follows:
private:
vector<vector<vector<shared_ptr<Room>>>> world;
In the same class, I provide access to Room objects:
public:
shared_ptr<Room> room_at(const int & x, const int & y, const int & z) const
{
return world.at(x).at(y).at(z);
}
Also in the same class, I initialize the world structure:
for (int x = 0; x < C::WORLD_X_DIMENSION; ++x)
{
vector<vector<shared_ptr<Room>>> row;
for (int y = 0; y < C::WORLD_Y_DIMENSION; ++y)
{
vector<shared_ptr<Room>> vertical_stack; // "stack"
for (int z = 0; z < C::WORLD_Z_DIMENSION; ++z)
{
vertical_stack.push_back(shared_ptr<Room>(nullptr));
}
row.push_back(vertical_stack);
}
world.push_back(row);
}
Later, I want to save a Room object into world:
void add_room_to_world(const int & x, const int & y, const int & z)
{
shared_ptr<Room> room = make_shared<Room>(); // create an empty room
/* (populate room's member fields) */
// add room to world
room_at(x, y, z) = room; // This doesn't work as expected
}
The shared_ptr within world starts out as nullptr as expected, but doesn't change on the last line above.
Based on what I've found on SO, I've tried operator= (above), .reset(room), and make_shared<Room>(room) (using an actual Room object rather than shared_ptr<Room>) but in all cases, the shared_ptr within world stays set to nullptr.
What is the correct way to assign objects into world?
room_at returns a value. When it is returned from the function it is copied, so any operations that you do on the returned value don't affect the original value. If you want to change the original value you have to return a reference like this:
shared_ptr<Room>& room_at(const int & x, const int & y, const int & z) const
{
return world.at(x).at(y).at(z);
}
If you don't want users of your class to be able to do this, declare this method private and keep the original as it is.
room_at returns a value. When you mutate this value, who cares? You're just mutating some random temporary. It has no meaning to the object it was copied from.
To support what you want, room_at would need to return a mutable reference- a very bad idea for a public API in this fashion.
You would want to offer an analagous private method that returns the mutable reference, and then implement room_at as just returning a copy of the object referenced by that function.

Can a "public:" function built into a class alter the class object it was called from?

apologies in advance, I feel like i'm missing something major here. Any time i call a function this way it fails to alter the objects member variable.
The easiest way for me to explain is to give an example:
class herp
{
private:
string derp;
public:
void mderp(herp x, string y) {x.derp = y;}
}
herp object_0;
string temp = "asdf";
object_0.mderp(object0, temp);
You are passing herp x as a value type. In this case x is a copy of whatever you pass in. If you want to directly access x.derp, you should pass x in as a reference:
void mderp(herp& x, string y) {x.derp = y;}
This should allow x.derp to be modified.
The argument herp to is passed by value, that means it is a copy of the original object_0. The mderp function modifies the copy, but that copy is thrown away immediately. Try a reference. I might do:
class herp
{
private:
string derp;
public:
static void mderp(herp &x, string y) {x.derp = y;}
}
herp object_0;
string temp = "asdf";
object_0.mderp(object0, temp);
Here the important thing is the change herp x -> herp& x which means the argument is "a reference to herp" rather than an actual herp value.
In this case I also made the method static, because it can be but that is not essential.
replace
x.derp = y;
with
this->derp = y;
What I get from your question, is that you want to initialize the private variable of your class. But there are a couple of things wrong here. You should read more about classes.
One way:
class herp
{
private:
string derp;
public:
void mderp(string y) {derp = y;}
};
herp object_0;
string temp = "asdf";
object_0.mderp(temp);
There are two things you should probably know.
First of all your object's member variable does not get changed because the way you wrote your code, your function mdepr creates a copy of the object herp. It then changes its member variable and destroys the object upon leaving the function. So if you want to keep your function the way it is you should use a reference or a pointer. Example:
void mderp(herp& x, string y) {x.derp = y;}
void mderp(herp* x, string y) {x->derp = y;}
The second thing is, based on your example usage of the function, you probably don't want a function like that. Member functions are meant to be used on a object and are allowed to modify it (unless they are const functions). So you can just write the following:
class herp
{
private:
string derp;
public:
void mderp(string y) {derp = y;}
}
herp object_0;
string temp = "asdf";
object_0.mderp(temp);
Hope this helps :)

c++ overload the [] operator for write/set

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.

C++ same function parameters with different return type

I need to find some way to mock an overload of a function return type in C++.
I know that there isn't a way to do that directly, but I'm hoping there's some out-of-the-box way around it.
We're creating an API for users to work under, and they'll be passing in a data string that retrieves a value based on the string information. Those values are different types. In essence, we would like to let them do:
int = RetrieveValue(dataString1);
double = RetrieveValue(dataString2);
// Obviously, since they don't know the type, they wouldn't use int =.... It would be:
AnotherFunction(RetrieveValue(dataString1)); // param of type int
AnotherFunction(RetrieveValue(dataString2)); // param of type double
But that doesn't work in C++ (obviously).
Right now, we're having it set up so that they call:
int = RetrieveValueInt(dataString1);
double = RetrieveValueDouble(dataString2);
However, we don't want them to need to know what the type of their data string is.
Unfortunately, we're not allowed to use external libraries, so no using Boost.
Are there any ways we can get around this?
Just to clarify, I understand that C++ can't natively do it. But there must be some way to get around it. For example, I thought about doing RetrieveValue(dataString1, GetType(dataString1)). That doesn't really fix anything, because GetType also can only have one return type. But I need something like that.
I understand that this question has been asked before, but in a different sense. I can't use any of the obvious answers. I need something completely out-of-the-box for it to be useful to me, which was not the case with any of the answers in the other question asked.
You've to start with this:
template<typename T>
T RetrieveValue(std::string key)
{
//get value and convert into T and return it
}
To support this function, you've to work a bit more, in order to convert the value into the type T. One easy way to convert value could be this:
template<typename T>
T RetrieveValue(std::string key)
{
//get value
std::string value = get_value(key, etc);
std::stringstream ss(value);
T convertedValue;
if ( ss >> convertedValue ) return convertedValue;
else throw std::runtime_error("conversion failed");
}
Note that you still have to call this function as:
int x = RetrieveValue<int>(key);
You could avoid mentioning int twice, if you could do this instead:
Value RetrieveValue(std::string key)
{
//get value
std::string value = get_value(key, etc);
return { value };
}
where Value is implemented as:
struct Value
{
std::string _value;
template<typename T>
operator T() const //implicitly convert into T
{
std::stringstream ss(_value);
T convertedValue;
if ( ss >> convertedValue ) return convertedValue;
else throw std::runtime_error("conversion failed");
}
}
Then you could write this:
int x = RetrieveValue(key1);
double y = RetrieveValue(key2);
which is which you want, right?
The only sane way to do this is to move the return value to the parameters.
void retrieve_value(std::string s, double& p);
void retrieve_value(std::string s, int& p);
<...>
double x;
retrieve_value(data_string1, x);
int y;
retrieve_value(data_string2, y);
Whether it is an overload or a specialization, you'll need the information to be in the function signature. You could pass the variable in as an unused 2nd argument:
int RetrieveValue(const std::string& s, const int&) {
return atoi(s.c_str());
}
double RetrieveValue(const std::string& s, const double&) {
return atof(s.c_str());
}
int i = RetrieveValue(dataString1, i);
double d = RetrieveValue(dataString2, d);
If you know your value can never be something like zero or negative, just return a struct holding int and double and zero out the one you don't need...
It's a cheap and dirty, but easy way...
struct MyStruct{
int myInt;
double myDouble;
};
MyStruct MyFunction(){
}
If the datastrings are compile-time constants (as said in answering my comment), you could use some template magic to do the job. An even simpler option is to not use strings at all but some data types which allow you then to overload on argument.
struct retrieve_int {} as_int;
struct retrieve_double {} as_double;
int RetrieveValue(retrieve_int) { return 3; }
double RetrieveValue(retrieve_double) { return 7.0; }
auto x = RetrieveValue(as_int); // x is int
auto y = RetrieveValue(as_double); // y is double
Unfortunately there is no way to overload the function return type see this answer
Overloading by return type
int a=itoa(retrieveValue(dataString));
double a=ftoa(retrieveValue(dataString));
both return a string.
As an alternative to the template solution, you can have the function return a reference or a pointer to a class, then create subclasses of that class to contain the different data types that you'd like to return. RetrieveValue would then return a reference to the appropriate subclass.
That would then let the user pass the returned object to other functions without knowing which subclass it belonged to.
The problem in this case would then become one of memory management -- choosing which function allocates the returned object and which function deletes it, and when, in such a way that we avoid memory leaks.
The answer is simple just declare the function returning void* type and in the definition return a reference to the variable of different types. For instance in the header (.h) declare
void* RetrieveValue(string dataString1);
And in the definition (.cpp) just write
void* RetrieveValue(string dataString1)
{
if(dataString1.size()<9)
{
static double value1=(double)dataString1.size();
return &value1;
}
else
{
static string value2=dataString1+"some string";
return &value2;
}
}
Then in the code calling RetrieveValue just cast to the right value
string str;
string str_value;
double dbl_value;
if(is_string)
{
str_value=*static_cast<*string>(RetrieveValue(str));
}
else
{
dbl_value=*static_cast<*double>(RetrieveValue(str));
}
Since you used an example that wasn't really what you wanted, you threw everyone off a bit.
The setup you really have (calling a function with the return value of this function whose return type is unknowable) will not work because function calls are resolved at compile time.
You are then restricted to a runtime solution. I recommend the visitor pattern, and you'll have to change your design substantially to allow for this change. There isn't really another way to do it that I can see.