I'm trying to return an std::vector that is inside a map but I don't seem to get it right.
The code below is what I have tried and the one further below is the test it's supposed to pass
namespace grade_school {
class school {
public:
inline std::map<int, std::vector<std::string>> roster () {return
MySchool;}
void add (std::string studentname , int grd);
std::vector<std::string>& grade (int grd);
private:
std::map<int,std::vector<std::string>> MySchool;
};
}
void grade_school::school::add (std::string studentname, int grd){
MySchool[grd].push_back(studentname);
}
std::vector<std::string>& grade (int grd) {
return MySchool[grd];
};
TEST_CASE("grade_returns_the_students_in_that_grade_in_alphabetical_order")
{
grade_school::school school_;
school_.add("Franklin", 5);
school_.add("Bradley", 5);
school_.add("Jeff", 1);
const auto actual = school_.grade(5);
const vector<string> expected{"Bradley", "Franklin"};
REQUIRE(expected == actual);
}
I expected that the return type would be the vector contained inside the map but the compiler error i got was error C2065: 'MySchool': undeclared identifier
I expected that the return type would be the vector contained inside the map.
This leaves room for interpretation, depending on how you interpret this sentence, this already is the case – or not...
std::vector<std::string> grade(int grd);
In C++, we speak of returning 'by value'. You get exactly the values that are in the map. But returning by value means, you get a copy of. If you now modify the returned value, you actually modify the copy, but not the vector in the map.
std::vector<std::string>& grade(int grd);
// ^ note the ampersand!
The ampersand denotes that we just return a reference to the vector in the map (in this case, it behaves similar to a pointer), and via the reference, you now can modify the vector in the map directly:
grade(7).push_back("seven");
For completeness: pointer:
std::vector<std::string>* grade(int grd) { return &mySchool[grd]; }
// need address-of operator: ^
grade(7)->push_back("seven");
Usually, one prefers the reference, but the pointer can be useful in some specific scenarios, e. g. you can return a nullptr (not possible with references) to denote that there is no suitable vector for some specific input.
In some use-cases, you might not want to allow to modify the vector returned. Returning by copy avoids that, but a copy might be expensive. To avoid copies and still disallow modifications, you can return by const reference:
std::vector<std::string> const& grade(int grd);
Admitted, a user might const_cast the const away, but then it's the user breaking a contract (returning something as const means tealling: 'Don't modify it, if you do so, your fault!').
Use reference type for return value:
std::map<int,std::vector<std::string>> MySchool;
std::vector<std::string>& grade (int grd) {
return MySchool[grd];
}
Using reference with containers and other enough big data objects is preferable due to perfomance. This minimize memory operations caused by data duplications.
Non const reference approach is good if you plan to modify vector outside of method or object which incapsulate this map. This is simple solution which always give you actual data and allow to modify.
Better approach is to incapsulate modifications of data in methods of class (or api function set) to avoid unexpected and unverified modificaions by user. Use return type const reference for that like this:
const std::vector<std::string>& grade (int grd)
If you really need to have a copy of array for that case you can do this simple by expression sintax. For example assign to value instead of reference:
// ref - is const reference to some array returned by function
const std::vector<std::string>& ref = grade(10)
// array - is a full copy of array pointed by reference returned from function
std::vector<std::string> array = grade(10)
When you return reference to container or some data you need to understand problem that user code save reference and it may be used multiple times. And during that time and dependent from how your container or your code manage data in memory it may bring to problem. So it is possible case when data at memory referenced by prevously returned reference is released. Returned before reference become refer to wrong memory. But user code may use that reference and bring to access violation or some undefined behaviour.
Even if your object guarantee that reference returned by method will exists during all object life time. Reference may be saved in the user code more long time than object itself. So there is no guarantee at all.
However we may use simple rule just to not save a reference in variable. Just use data in same expression with function call always:
grade(10).length()
std::accumulate(grade(10).begin(), grade(10).end(), 0)
However user may do not know or forget this rule.
And of course your function must always return reference to existing data. For example if no such array at specified index you need to create appropriate array at specified index and use it for return.
And of course function must not return reference to any non-static variable declared in function body because all of them will be destroyed after function return and before return value will be used. Which guarantee crash of aplication. Use return by value for that case.
Related
I'm new to C/C++, so people excuse me if this is a noob question.
I have a controller class, which has a private member variable which is a vector<Contact> contacts. The class has methods which allow us to change the state of this vector (standard CRUD operations).
The class has a public method called get_contacts() which returns this private vector of objects:
std::vector<Contact> Contacts_Controller::get_contacts() const {
return this->contacts;
}
I have a method which adds the contact to this private vector via push_back(). The issue is that if the add_contact() method uses the accessor method, then the class variable does not get updated:
void Contacts_Controller::add_contact(const Contact &contact) {
this->get_contacts().push_back(contact);
}
I assume this is a memory issue, perhaps I have some issues with my use of const or I'm not correctly using references, because the following code works exactly as expected:
void Contacts_Controller::add_contact(const Contact &contact) {
this->contacts.push_back(contact);
}
Using either method won't return any errors, but if I then request the vector of contacts after using the first method it'll be empty, whereas the second method correctly adds data to the vector.
Again, sorry if this is a noob question, but I'm completely stumped, and I wouldn't know what to search for! How would I fix this referencing issue?
"The class has a public method called get_contacts() which returns this private vector of objects"
Nope, it returns a copy. You need to return by reference to get the actual member:
std::vector<Contact>& Contacts_Controller::get_contacts(){
return this->contacts;
}
Note that I removed the const, otherwise you'd have to mark the return as const also and you wouldn't be able to modify it.
The issue is that your function is returning the vector by value, which means the calling function gets a copy.
When you call push_back() on it, only the copy gets the extra member.
Your function could return a reference. Then your user can call push_back(). If it is a member variable of your class and you are returning a non-const reference (which you must to allow the modification) your function will probably also be non-const.
Thus:
std::vector<Contact> & Contacts_Controller::get_contacts() // not const
{ return this->contacts; }
You can also have a read-only version, as an overload.
std::vector<Contact> const & Contacts_Controller::get_contacts() const
{ return this->contacts; }
This version allows read-only access to the contacts and can also be a const member function.
When you call get_contacts, you return a copy of this->contacts. If you want to share a vector, either return a reference to it (but you must be sure that your reference will stay valid so your class instance won't be moved or copied), or use a smart pointer to dynamically allocate the space for your vector and extend its lifetime until the last reference to it has been destructed. In this case use a member with type std::shared_ptr<std::vector<Contact> >
Given the example:
inline string &GetLabel( ) {
return m_Label;
};
Where m_Label is a private class member variable.
The way I think I understand it, this function will return a reference to the variable m_Label. What would be the implications of using this throughout my program and would it be a better to just return the value, instead of the reference? Thank you!
The ampersand isn't before the function name so much as it's after the return type. it returns a reference to a string.
The implication of this is that a caller of this function could modify the value of m_label through the reference. On the other hand, it avoids copying the string. You might want the reference and the function to be const, like so:
inline const string& GetLabel() const
{
return m_Label;
}
Best of both worlds. You avoid the copy, but callers can't change your object.
It returns a reference to the private member.
There are many cases where this is desirable, but some care should be taken.
IMO it's generally not a good idea to return a copy of an internal object that is not an integral type, for overall performance reasons. Yes I know, premature optimization is not good, but this is not really optimization, it's just a good performance practice that allows the caller to determine the performance implications; if it wants a copy, it can just not declare the variable that it's assigning it to as a reference.
There are 2 general rules of thumb I use here:
1) If you don't want the caller to be able to modify the private object directly, declare the return value as a const reference:
inline const string& GetLabel() const{ return m_Label; }
2) A caller should never store the reference returned from a class method, it should only be used locally where the parent object is guaranteed to be in scope.
If for some reason you need callers to be able to store a reference to your internal objects, use smart pointers instead.
Returning a reference means that the calling code can modify the value of your member variable after you return. That's very dangerous, unless you intended for that to happen.
Better is a const reference, or return by value (without the &).
One implication is that if the enclosing object is destructed, the reference becomes invalid:
Object* o = new Object;
string& label = o->GetLabel();
delete o;
// label becomes a dangling reference here.
Another implication is that a caller may modify the string. You can remedy that by returning a const reference.
You're are correct. It's a reference to the string member.
The implication will be that if a caller were to assign a value or otherwise modify the returned string that they would also be modifying the member variable. If this is not the intent you may want to return a copy by value to avoid breaking encapsulation.
Suppose I have a class Foo with a std::string member str. What should get_str return?
std::string Foo::get_str() const
{
return str;
}
or
const std::string& Foo::get_str() const
{
return str;
}
What is more idiomatic in C++?
The short answer is: it depends :-)
From the performance point of view returning a reference is (usually) better: you save the creation of a new std::string object. (In this case, the creation is costly enough and the size of the object is high enough to justify make this choice at least worth considering - but this is not always the case. With a smaller or built-in type the performance difference may be negligible, or returning by value may even be cheaper).
From the security point of view returning a copy of the original value may be better, as constness can be cast away by malicious clients. This is especially to be taken into consideration if the method is part of a public API, i.e. you(r team) have no full control over how the returned value is (mis)used.
One of the goals of having an accessor method is to try, at least to some extent, to abstract your class implementation from its interface.
Returning by value is better because there are no lifetime issues with the referenced object. Should you decide not to have a std::string member but, say, a std::stringstream or to create a std::string on the fly you don't have to change the interface.
Returning by const reference isn't the opposite of taking a parameter by const reference, taking a value by const reference doesn't tie your internal data representation to the external interface.
In general (unless there's a proven performance issue) I would return by value.
First of all there's a semantic difference, if your property changes do you want your clients to be updated of the change or get the value at the moment of calling the function?
There's the obvious correctness issue, if you return by reference the entity calling the function may hold on to the reference and may use it after your object was destructed (which is not so good).
Another problem is with multiple threaded code, if one thread reads from the const reference while you're updating the variable your in for lots of trouble.
In any case I think the most common use case is when the caller of the function stores the value in a variable.
string val = obj->get_str();
// use val now
If this is true (as opposed to cout << obj->get_str() where there is no variable) you always have to construct a new string for val even if you return by reference and since compilers can perform RVO the by-value version will not under-perform the by-const-ref variant.
In conclusion: if you know it's a performance issue and you are sure that the return value will not be stored for longer than your object will exist and you don't expect to be used from different threads, then it's OK to return by const reference.
Returning by value means you do not have to have an internal std::string stored somewhere in the class for which you return.
In a pure virtual method it is preferable not to assume that the std::string will be there and therefore to return a std::string by value.
In a concrete class where there is clearly a std::string member and you are just going to return a reference to it, you can, for efficiency, return it by const reference. Even if you have to change it later, you do not need to change functionality that uses the class.
In a multi-threaded model where the inner string might change between calls, of course, you probably need to return by value (assuming that users of the class will get a "snapshot" view of the string value at the time of the completion of the call).
Returning by reference is usually more efficient. I do however have a non-mutable reference-counted string class that you can return by value efficiently and I used to use that quite frequently.
By the way, some would recommend returning a std::string by const value. I do not think it is the best way to do it, as it prevents allowing the user to "swap" it into a local variable.
AFAIK, the rule is same as the one which is used while deciding whether to take a function parameter by value or const reference. If the sizeof the value being returned is small enough then I tend to use returning a copy else return a const reference.
Generally you should return PODs by value (e.g, int, short, char, long etc,) and a const reference for more complex types:
int getData() const;
short getMoreData() const;
const std::string& getName() const;
const ComplexObject& getComplexData() const;
I believe the second implementation (const reference) is correct as:
the returned object is immutable and therefore upholds the rules of encapsulation.
it's slightly more efficient as there is no copying of str.
However the first approach will work almost as well.
It depends on what you want to do with the return value.
This is better if you just want to make a query and not modify str.
const std::string& Foo::get_str() const
{
return str;
}
Otherwise, go for this:
std::string& Foo::get_str()
{
return str;
}
And if you want a copy/clone of str, then use this:
std::string Foo::get_str() const
{
return str;
}
I am programming in C++ more then 5 years, and have never met any place where reference of the variable is recommended to use except as a function argument (if you don't want to copy what you pass as your function argument). So could someone point cases where C++ variable reference is recommended (I mean it gives any advantage) to use.
As a return value of an opaque collection accessor/mutator
The operator[] of std::map returns a reference.
To shorten the text needed to reference a variable
If you miss old-school with Foo do ... statement (that's Pascal syntax), you can write
MyString &name = a->very->long_->accessor->to->member;
if (name.upcase() == "JOHN") {
name += " Smith";
}
another example of this can be found in Mike Dunlavey's answer
To state that something is just a reference
References are also useful in wrapper objects and functors--i.e. in intermediate objects that logically contact no members but only references to them.
Example:
class User_Filter{
std::list<User> const& stop_list;
public: Functor (std::list<User> const& lst)
: stop_list(lst) { }
public: bool operator()(User const& u) const
{ return stop_list.exists(u); }
};
find_if(x.begin(),x.end(),User_Filter(user_list));
The idea here that it's a compile error if you don't initialize a reference in constructor of such an object. The more checks in compile time--the better programs are.
Here's a case where it's handy:
MyClass myArray[N];
for (int i = 0; i < N; i++){
MyClass& a = myArray[i];
// in code here, use a instead of myArray[i], i.e.
a.Member = Value;
}
Use references wherever you want, pointers when you are forced to.
References and pointers share part of their semantics: they are an alias to an element that is not present. The main difference is with memory managements: references express clearly that you are not responsible for the resource. On the other hand, with pointers it is never really clear (unless you mean smart pointers): are you assumed to delete the pointer or will it be deleted externally?
You must use pointers when you must manage memory, want to allow for optional semantics or need to change the element referred to at a later time.
In the rest of cases, where you can use a reference or a pointer, references are clearer and should be preferred.
Now, as you point out, they are really not needed: you can always use pointers for all the reference uses (even parameter passing), but the fact that you can use a single tool for everything does not mean there are no better suited tools for the job.
I tend to use reference members instead of pointers for externally controlled non-optional construction parameters.
EDIT (added example):
Let's say that you have a database and a DAO class having the database as a dependency:
struct Database {};
struct PersonDao {
const Database &m_d;
PersonDao(const Database &d): m_d(d) {}
};
Furthermore, the scope of the database is controlled externally from the DAO:
int main() {
Database d;
PersonDao pd(d);
}
In this case it makes sense to use a reference type, since you don't ever want DAO::m_d to be null, and its lifetime is controlled externally (from the main function in this case).
I use references in function arguments not just to avoid copies but also instead of pointers to avoid having to deal with NULL pointers where appropriate. Pointers model a "maybe there's a value, but maybe not (NULL)", references are a clear statement that a value is required.
... and to make it absolutely clear (-> comments). I tend to avoid pointers to model "maybe there are several values" - a vector is a better option here. Pointers to several values often end up in C-style programming because you usually have to pass the # of elements as well separately.
Use a const reference to give a name to a value, e.g.:
const Vec3 &ba=b-a;
This names the value, but doesn't necessarily create a variable for it. In theory, this gives the compiler more leeway and may allow it to avoid some copy constructor calls.
(Related non-duplicated Stack Overflow question at Const reference to temporary. The Herb Sutter link there has more information about this.)
The argument to the copy-constructor MUST be passed as a reference, since otherwise the copy constructor would need to call it self in an endless recursion (stack overflow).
I tend to agree, but perhaps const return values.
Well you kind of have two choices for aliasing other values(ignoring shared_ptrs and the like): pointers and references.
References must be initialized at construction to refer to something else. So semantically a reference can never be NULL. In reality, though, the underlying data can go away, giving you problems often more difficult to debug than if a pointer went away. So I'm not sure there's a real advantage here unless you were disciplined and consistent with how they were used vis-a-vis referring to items that were dynamically allocated. If you did this with pointers too, you'd avoid the same problems.
Perhaps more importantly, references can be used without thinking about all the issues that arise with pointers. This is probably the main advantage. Semantically a reference is the thing. If you guarantee as the caller/callee that the underlying memory doesn't go away, you don't have to confuse the user with any of the questions that come along with pointers (Do I need to free this? Could this be NULL? etc) and can safely use a reference for convenience.
An example of this might be a function that looks up the corresponding string for an enum,
const std::string& ConvertToString( someEnum val)
{
static std::vector< std::string > lookupTable;
if (lookupTable.empty())
{
// fill in lookup table
}
// ignoring the cast that would need to happen
return lookupTable[val]
}
Here the contract between the caller and the callee guarantees that the return type will always be there. You can safely return a reference, and avoid some of the questions that pointers invite.
References make code prettier. So use them whenever it takes a reference to beautify your code.
i would like to enlist some cases:
1) while writing singleton classes
class singleton
{
singleton();
explicit singleton(const singleton&);
singleton& operator=(const singleton&);
public:
static singleton& instance()
{
static singleton inst;
return inst;
}
};// this is called the 'Meyers' singleton pattern. refer to More Effective C++ by Scott Meyers
it has all the benefits, but avoids using the new operator
**2)**here is no such thing as a null reference. A reference must always refer to some object. As a result, if you have a variable whose purpose is to refer to another object, but it is possible that there might not be an object to refer to, you should make the variable a pointer, because then you can set it to null. On the other hand, if the variable must always refer to an object, i.e., if your design does not allow for the possibility that the variable is null, you should probably make the variable a reference
**3)**Because a reference must refer to an object, C++ requires that references be initialized:
string& rs; // error! References must
// be initialized
string s("xyzzy");
string& rs = s; // okay, rs refers to s
Pointers are subject to no such restriction
The fact that there is no such thing as a null reference implies that it can be more efficient to use references than to use pointers. That's because there's no need to test the validity of a reference before using it
**4)**Another important difference between pointers and references is that pointers may be reassigned to refer to different objects. A reference, however, always refers to the object with which it is initialized: ¤ Item M1, P10
string s1("Nancy");
string s2("Clancy");
string& rs = s1; // rs refers to s1
string *ps = &s1; // ps points to s1
rs = s2; // rs still refers to s1,
// but s1's value is now
// "Clancy"
ps = &s2; // ps now points to s2;
// s1 is unchanged
Stream operators are an obvious example
std::ostream & operator<< (std::ostream &, MyClass const &...) {
....
}
mystream << myClassVariable;
You obviously don't want a pointer as checking for NULL makes using an operator very tedious i.s.o. convenient
I've used a reference to an ostream instead of a pointer. I supppose that I prefer references to pointers when the class has a lot of operators.
What's better as default, to return a copy (1) or a reference (2) from a getter function?
class foo {
public:
std::string str () { // (1)
return str_;
}
const std::string& str () { // (2)
return str_;
}
private:
std::string str_;
};
I know 2) could be faster but don't have to due to (N)RVO. 1) is safer concerning dangling references but the object will probably outlife or the reference is never stored.
What's your default when you write a class and don't know (yet) whether performance and lifetime issues matter?
Additional question: Does the game change when the member is not a plain string but rather a vector?
Well it really depends on what you expect the behaviour to be, by default.
Do you expect the caller to see changes made to str_ unbeknownst(what a word!) to them? Then you need to pass back a reference. Might be good if you can have a refcounted data member and return that.
If you expect the caller to get a copy, do 1).
My rule of thumb is to return a copy for simple basic datatypes such as int, string etc. For a bit more complicated structures where copying may be costlier (like vector you mentioned) I prefer to return a const-reference.
The compiler will not be able to perform (N)RVO in this case. The (named) return value optimization is an optimization where the compiler creates the function auto variables in the place of the return value to avoid having to copy:
std::string f()
{
std::string result;
//...
return result;
}
When the compiler sees the code above (and assuming that if any other return is present it will also return the result variable) it knows that the variable result has as only possible fate being copied over the returned temporary and then destroyed. The compiler can then remove the result variable altogether and use the return temporary as the only variable. I insist: the compiler does not remove the return temporary, it removes the local function variable. The return temporary is required to fulfill the compilers call convention.
When you are returning a member of your class, the member must exist, and the call convention requires the returned object to be in a particular location (stack address usually). The compiler cannot create the method attribute over the returned object location, nor can it elide making the copy.
I'm returning a reference, because a string seems not "cheap to copy" to me. It's a complex data type with dynamic memory management and all that.
The "if you want the caller to get a copy, you should return by value" argument is moot, because it doesn't preclude copies at all. The caller can still do the following and get a copy anyway
string s = obj.str();
You need to explicitly create a reference on the caller side to be able to refer to the data member directly afterwards - but why would you do that? There definitely are enough user defined types that are cheap to copy
Smart Pointers
Iterators
All of the non-class types.
Returning a reference to an object's internals as part of its public interface can be a code smell if not outright bad design.
Before returning a reference to an internal object in a public interface, the designer should pause. Doing so couples users of your class to part of your design. Often it is outright unnecessary, sometimes it indicates further design work is needed. At times it is necessary, as commenters have noted.
If there is no special reason to use a value type as return value, I always return a const reference. If I need (or expect to need) a (writable) copy, I add a copy ctor and an assignment operator to the returned class if not already available. For the usage think of:
const MyClass & ref = container.GetAt( 1234 ); // need only reference
MyClass copy = container.GetAt( 1234 ); // get writable copy
Actually this is quite straight forward, isn't it?
if its a small basic type - primatives like int and long and their wrappers and other basic things like 'Point' - return a copy
if its a string, or any other complex type - return a reference.
The only problem I have with returning a const-reference, which is something I would typically do for non basic types, is that there is nothing to stop the caller removing the "const"ness and then modifying the value.
Personally, I'd suggest that such code is a bug. If they know you're returning a reference and continue to cast away the const then it's on their head.