开发者

Correct way to return stl map by reference / Is this behavior well defined?

开发者 https://www.devze.com 2023-04-05 03:15 出处:网络
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:

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:

  1. Major: a::get() should be const:

    const map<string, vector<string> > & get() const // note the const at the end
    
  2. Minor: I would create an alias for the map's type using typedef.

    typedef map<string, vector<string> > my_map_t;
    
  3. 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消