I have a class defined like:
class Foo
{
public:
void ReturnReferenceToMember(???)
{
??? // Give caller a reference to member variable m_x
}
private:
std::unordered_map<int, int> m_x;
}
What's the C++ way to implement the ????
I don't want to copy the internals of the map, and I also want to keep being able to use the map inside the class. I don't understand move mechanics that well, but it seems to me like the second requirement negates std::move...
It is not possible to pass a reference that can be changed. That would mean passing a pointer to a reference, or a reference to a reference - both of those are invalid in C++.
The usual approach is to return a reference, not (since it can't be done) to pass one in the hope of it being changed.
std::unordered_map<int, int>& ReturnReferenceToMember()
{
return m_x;
}
If you expect to pass an argument that can be changed in order to permit the caller to access class internals, it is necessary to use a pointer to a pointer
// double indirection needed as pointers are passed by value too
void ReturnPointerToMember(std::unordered_map<int, int> **p)
{
*p = &mx;
}
or a reference to a pointer
void ReturnPointerToMember(std::unordered_map<int, int> *&p)
{
p = &mx; // note the missing asterisk compared with passing pointer to pointer
}
If you don't wish the caller to change class internals, it is necessary to const-qualify the above in various ways.
void ReturnReferenceToMember(std::unordered_map<int, int>** outMap)
{
*outMap = &m_x;
}
void ReturnReferenceToMember(const std::unordered_map<int, int>** outMap) const
{
*outMap = &m_x;
}
I overloaded it on const intentionally, so you can use either form depending on whether the Foo you have is const.
As you can see, we are not really using references here, because those cannot be reseated, but the caller can still use them:
std::unordered_map<int, int>* mapPtr = nullptr;
ReturnReferenceToMember(&mapPtr);
if (mapPtr)
{
std::unordered_map<int, int>& mapRef = *mapPtr;
// now you have your reference
}
Related
I was wondering if the following is correct usage of a std::shared_ptr.
All I want to do with the originally created pointer is add it onto the vector on class A,
which will be later on retrieved
class A
{
public:
void AddToVec(std::shared_ptr<B> b)
{
myVec_.push_back(b);
}
std::vector<std::shared_ptr<B>> GetVec()
{
return myVec_;
}
private:
std::vector<std::shared_ptr<B>> myVec_;
}
Then on main, a pointer is created and passed with the following way
int main()
{
A a;
std::shared_ptr<B> ptr = std::make_shared<B>();
a.AddToVec(std::move(ptr));
}
Is the usage of the std::move correct on the main function?
Is it okay to simply create the std::shared_ptr on main and move ownership using the AddToVec function?
Is the usage of the std::move correct on the main function?
Yes, it is correct. If you do not use the std::move, it will also compile; however, it increases the reference count of std::shared_ptr.
Is it okay to simply create the shared ptr on main and move ownership using the AddToVec function?
It is correct in the sense, you do not want to increment the reference count of the std::shared_ptr.
The same you need inside AddToVec, as the b is lvalue reference inside the function scope. Therefore, you need to explicitly std::move into the myVec_ as follows:
void AddToVec(std::shared_ptr<B> b)
{
myVec_.push_back(std::move(b));
}
Also note that the GetVec will return each time a copy of the member myVec_, which you might not want. Therefore, you might need one or both the following
// non-const reference to the member
std::vector<std::shared_ptr<B>>& GetVec()
{
return myVec_;
}
// const reference to the member
const std::vector<std::shared_ptr<B>>& GetVec() const /* noexcept */
{
return myVec_;
}
I have defined a class that holds a reference to a list of static functions which are defined
outside of the class. These functions each take a pointer to that particular instance of the class as a argument.
I'm passing the this pointer to the functions. But that doesn't seem right to me.
Is there a better way?
The code below is a simplified version:
#include <iostream>
#include <map>
class A
{
public:
typedef void (*action_func)(A*);
typedef std::map<int, action_func> func_map;
A(func_map the_map)
:m_map(the_map)
{}
void execute_action(int action_id)
{
auto it = m_map.find(action_id);
if(it != m_map.end())
{
auto cmd = it->second;
cmd(this);
}
}
private:
func_map& m_map;
};
static void function_1(A* ptrToA)
{
std::cout << "This is function_1\n";
}
static void function_2(A* ptrToA)
{
std::cout << "This is function_2\n";
}
static func_map functions =
{
{1, function_1},
{2, function_2}
};
int main()
{
A obj(functions);
obj.execute_action(1);
obj.execute_action(2);
return 0;
}
The output of the above is this:
This is function_1
This is function_2
When storing references and pointers to things outside the class it is important to reason about their lifetimes. Generally, the thing being referenced should outlive the thing that references it.
In your particular case, static func_map functions; has static storage duration, that is it is created before main() starts and is destroyed after main() ends.
So you can safely use it inside A obj, which lives within the scope of main():
int main()
{
A obj(functions);
. . .
}
However, the constructor of A isn't just storing it - it stores a reference to its temporary copy instead:
A(func_map the_map)
:m_map(the_map)
{}
func_map& m_map;
What's worse, the temporary copy lives only until the end of the full-expression, i.e. until the end of A obj(functions);. So if you use it after that you will be accessing a dangling reference (undefined behavior).
To fix that, change it to a pass by-reference:
A(func_map& the_map)
:m_map(the_map)
{}
func_map& m_map;
Now there's no issue.
I'm passing the this pointer to the functions. But that doesn't seem right to me.
The same lifetime reasoning applies - if the thing where you pass this into doesn't use it for longer than this is alive, then technically there is no issue. In your case the function calls are synchronous, so by definition this is alive during each function call.
Whether or not it's "right" from a design perspective is impossible to say from the provided example. There could be better solutions, but there are also design patterns (e.g. Strategy Pattern) that are based on passing a reference to self around. So in the end it's a design choice.
const references make sure you can't change the object you're referring to. For example:
int i = 1;
const int& ref = i;
ref = 42; // error, because of a const reference
But if you use a reference to a pointer or a unique_ptr, you can. Example:
class TinyClass {
public:
int var = 1;
void f1() { var = 42; }
};
std::unique_ptr<TinyClass> pointer(new TinyClass);
const std::unique_ptr<TinyClass>& constRef = pointer;
constRef->f1(); // no error
I assume this happens because the pointer itself wasn't changed. But this feels misleading, or like an easy mistake. Is there a simple way to declare a "real" const reference to a pointer? As in: makes sure the object itself is const.
edit: Assume that I can't just change the type of the unique_ptr. A real-world scenario would be that some objects are constructed in a vector<unique_ptr<C>> and some function gets a (const) reference to one of its elements.
The const in const std::unique_ptr<TinyClass>& constRef guarantees that constRef will not point to another object once it set up. It has nothing to do with the object itself.
If you want to prevent changing the object itself:
std::unique_ptr<const TinyClass> ptr_to_const_object;
Edit (after OP's edit):
You can not do anything. Since there is a function which wants const vector<unique_ptr<C>>&, the function clearly tells you that it needs to play with the object inside the pointer (and even the pointer) but it does not need to change the vector items (like adding new item or deleting it).
Let's say I have a class Position:
class Position{
public:
Position(int x, int y) : x(x), y(y) {}
int getX(void) { return x; }
int getY(void) { return y; }
private:
int x;
int y;
};
and a class Floor:
class Floor {
public:
Floor(Position p) : position(p) { }
private:
Position position;
};
If I were to add a getter like getPosition(void), what should it return?
Position? Position*? Position&?
And should I have Position position or Position* position as instance variable? Or Position& position?
Thanks.
By default, if you want a value of type T, use a data member of type T. It's simple and efficient.
Position position;
Usually, you will want to return this by value or by reference to const. I tend to return objects of fundamental type by value:
int getX() const
{
return x;
}
and class objects by reference to const:
Position const& getPosition() const
{
return position;
}
Objects that are expensive to copy will often benefit from being returned by reference to const. Some class objects may be quicker to return by value, but you'd have to benchmark to find out.
In the less common case where you want to allow the caller to modify your data member, you can return by reference:
Position& getPosition()
{
return position;
}
However, it is usually better prevent direct access to class internals like this. It gives you more freedom to change implementation details of your class in the future.
If you need to dynamically allocate the value for some reason (e.g. the actual object may be one of a number of derived types at determined at runtime), you can use a data member of std::unique_ptr type:
std::unique_ptr<Position> position;
Create a new value using std::make_unique:
Floor() :
position(std::make_unique<FunkyPosition>(4, 2))
{
}
Or move in an existing std::unique_ptr:
Floor(std::unique_ptr<Position> p) :
position(std::move(p))
{
}
Note that you can still return by value or reference to const:
Position const& getPosition() const
{
return *position;
}
That is, as long as position cannot contain nullptr. If it can, then you may want to return a pointer to const:
Position const* getPosition() const
{
return position.get();
}
This is a genuine use of raw pointers in modern C++. Semantically, this communicates to the caller that the value returned is "optional" and may not exist. You should not return a reference to const std::unique_ptr<T>, because you can actually modify the value it points to:
std::unique_ptr<Position> const& getPosition() const
{
return position;
}
*v.getPosition() = Position(4, 2); // oops
In addition, returning a std::unique_ptr would once again expose unnecessary implementation details, which you should prefer not to do.
It is also possible for multiple objects to own the same dynamically-allocated object. In this case, you can use std::shared_ptr:
std::shared_ptr<Position> position;
Create a new value using std::make_shared:
Floor() :
position(std::make_shared<FunkyPosition>(4, 2))
{
}
Or copy/move in an existing std::shared_ptr:
Floor(std::shared_ptr<Position> p) :
position(std::move(p))
{
}
Or move in an existing std::unique_ptr:
Floor(std::unique_ptr<Position> p) :
position(std::move(p))
{
}
Only once all std::shared_ptrs pointing to an object have been destroyed is the object itself destroyed. This is a far heavier-weight wrapper than std::unique_ptr so use sparingly.
In the case where your object is referencing an object it doesn't own, you have several options.
If the referenced object is stored in a std::shared_ptr, you can use a data member of type std::weak_ptr:
std::weak_ptr<Position> position;
Construct it from an existing std::shared_ptr:
Floor(std::shared_ptr<Position> p) :
position(std::move(p))
{
}
Or even another std::weak_ptr:
Floor(std::weak_ptr<Position> p) :
position(std::move(p))
{
}
A std::weak_ptr does not own the object it references, so the object may or may not have been destroyed, depending on whether all its std::shared_ptr owners have been destroyed. You must lock the std::weak_ptr in order to access the object:
auto shared = weak.lock();
if (shared) // check the object hasn't been destroyed
{
…
}
This is super safe, because you cannot accidentally dereference a pointer to a deleted object.
But what if the referenced object is not stored in a std::shared_ptr? What if it is stored in a std::unique_ptr, or isn't even stored in a smart pointer? In this case, you can store by reference or reference to const:
Position& position;
Construct it from another reference:
Floor(Position& p) :
position(p)
{
}
And return by reference to const as usual:
Position const& getPosition() const
{
return position;
}
Users of your class have to be careful though, because the lifetime of the referenced object is not managed by the class holding the reference; it's managed by them:
Position some_position;
Floor some_floor(some_position);
This means that if the object being referenced is destroyed before the object referencing it, then you have a dangling reference which must not be used:
auto some_position = std::make_unique<Position>(4, 2);
Floor some_floor(*some_position);
some_position = nullptr; // careful...
auto p = some_floor.getPosition(); // bad!
As long as this situation is carefully avoided, storing a reference as a data member is perfectly valid. In fact, it is an invaluable tool for efficient C++ software design.
The only problem with references is that you cannot change what they reference. This means that classes with reference data members cannot be copy assigned. This isn't a problem if your class doesn't need to be copyable, but if it does, you can use a pointer instead:
Position* position;
Construct it by taking the address of a reference:
Floor(Position& p) :
position(&p)
{
}
And we return by reference to const as before:
Position const& getPosition() const
{
return *position;
}
Note that the contructor takes a reference, not a pointer, because it prevents callers from passing a nullptr. We could of course take by pointer, but as mentioned earlier, this suggests to the caller that the value is optional:
Floor(Position* p) :
position(p)
{
}
And once again we may wish to return by pointer to const:
Position const* getPosition() const
{
return position;
}
And I think that's it. I spent far longer writing this (probably unnecessarily detailed) answer than I intended to. Hope it helps.
What kind of a return type does the following function prototype have?
int const& myfunctionname(int i)
I am not getting the use of the const and & here. If I am returning objects/arrays/ basically non-local variables, should I use a pointer or a reference if I want to return the location of the object?
It means you're returning a reference to a value that cannot be changed.
If you return a reference to a local variable then you're going to have a problem, as it will reference something that no longer exists:
int const &GetValue()
{
int x = 10;
return x; // THIS IS BAD!
}
Also, it doesn't really make sense to return const references to the integral types (int, long, etc) as they take pretty much the same space as the reference in the first place. However if you do then it's not a big deal.
If you're returning non-local data (ie member data) then use references if the data will always exists, and use pointers if the data may not exist, so that NULL indicates the absence of the data. For example:
const std::string &User()const
{
return m_Username;
}
int Age() const
{
return m_Age; // Pointless to use a reference here
}
const Person *Partner()const
{
return m_Parter; // User may not have a partner, so pointer
}
Make the pointer or reference const if you don't want the caller to be able to modify the object returned.
Such function can return a reference to a member variable of the class it belongs to, but the calling function will not be able to change it. For example:
class Foo
{
public:
Foo() {boo=5;}
public:
int const& myfunctionname(int i) {boo += i; return boo;}
private:
int boo;
}
void func(Foo& foo)
{
const int& a = foo.myfunctionname(6);
a += 7; // Compilation error
int b = a+7; // OK
}
Supplemental:
The most common example of returning a constant value by reference, is probably operator++().