Correct way to return stl map by reference / Is this behavior well defined?
I have 2 classes and one of them has map<string, vector<string> >
I want to be able to use this in other class. Here is my code:
class a
{
map<string, vector<string> > m;
public:
const map<string, vector<string> > & get()
{
return m;
}
};
class b
{
a obj;
public:
void test()
{
map<string, vector<string> > 开发者_运维问答m= obj.get();
// and then print
}
};
int main(int argc, char ** argv)
{
b bobj;
bobj.test();
return 0;
}
Is the way I returned reference to map in class a
correct? It worked,but I just want to confirm if it was done properly / I got lucky / any other comments about the code.
Thank you for your help.
If you do not want to change the map in b::test()
, you should not make a copy of it:
const map<string, vector<string> >& m = obj.get(); // note the const &
My objections:
Major:
a::get()
should beconst
:const map<string, vector<string> > & get() const // note the const at the end
Minor: I would create an alias for the map's type using
typedef
.typedef map<string, vector<string> > my_map_t;
Minor: I can't see at all what
b
is for.
Given these, my code would look like this:
class a
{
public:
typedef map<string, vector<string> > my_map_t;
const my_map_t & get() const {return m;}
private:
my_map_t m;
};
void test(const a& obj)
{
const a::my_map_t& m = obj.get();
// and then print
}
int main()
{
a obj;
test(obj);
return 0;
}
Yes, that is the correct way to return a reference to a constant object.
However, in your test
function where you receive the returned reference, the left hand side is not a reference. That means you're actually going to create a copy of the entire map in this function. A simple change will fix that problem, and then the test
function becomes zero copy:
void test()
{
map< string, vector<string> > const & m = obj.get();
// and then print
}
It is correct, but you should use a reference to store the result of obj.get()
, as mentioned previously. It would have been incorrect if you would have done something like this:
const map< string, vector<string> >& foo()
{
map< string, vector<string> > m;
// ...
return m;
}
because, in this case, m
will not exist anymore after foo()
completes execution.
Instead of directly answering your question, let me show you a very simple example. Consider a simple class A having a double as its private member.
class A{
private:
double a;
public:
A(double _a);
double
get_a();
double&
get_aref();
const double&
get_aconstref();
};
The implementation of that class. Very simple
A::A(double _a): a(_a){
};
// Getters
double
A::get_a() {
return a;
}
double&
A::get_aref(){
return a;
}
const double&
A::get_aconstref(){
return a;
}
Now lets get to the main program that uses class A.
int main(){
A ainst(6.0);
double a = ainst.get_a();
std::cout << "a = " << a << std::endl;
a++;
std::cout << "a+1 = " << a << std::endl;
std::cout << "Meanwhile, in class A, value of a = " << ainst.get_a() << std::endl;
double& aref = ainst.get_aref();
std::cout << "aref = " << aref << std::endl;
aref++;
std::cout << "aref+1 = " << aref << std::endl;
std::cout << "Meanwhile, in class A, value of a = " << ainst.get_a() << std::endl;
const double& aconstref = ainst.get_aconstref();
std::cout << "aconstref = " << aconstref << std::endl;
// aconstref++;
// std::cout << "aconstref+1 = " << aconstref << std::endl;
std::cout << "Meanwhile, in class A, value of a = " << ainst.get_a() << std::endl;
return 0;
}
So you can only do a
const double& aconstref = ainst.get_aconstref();
and not
double& aconstref = ainst.get_aconstref();
if a method of a class returns one of the class members of type T in the form const T&, it means that it does not want the caller to change that member. In the above example, T is a double. Substitute a std::map in nits place and the same logic holds. I hope that is pretty explanatory. If you remove the two commented lines, the compiler complains since you are trying to change that reference.
精彩评论