通过引用返回stl映射的正确方法/这个行为是否定义良好?

时间:2011-09-16 11:41:07

标签: c++ stl reference

我有2个类,其中一个有map<string, vector<string> >我希望能够在其他课程中使用它。这是我的代码:

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;
}

我在class a中返回对地图的引用是否正确?它有效,但我只想确认它是否正确完成/我很幸运/有关代码的任何其他评论。

感谢您的帮助。

4 个答案:

答案 0 :(得分:13)

如果您不想更改b::test()中的地图,则不应复制该地图:

const map<string, vector<string> >& m = obj.get(); // note the const &

我的反对意见:

  1. 专业:a::get()应为const

    const map<string, vector<string> > & get() const // note the const at the end
    
  2. 次要:我会使用typedef为地图的类型创建别名。

    typedef map<string, vector<string> > my_map_t;
    
  3. 轻微:我完全看不出b的用途。

  4. 鉴于这些,我的代码看起来像这样:

    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;
    }
    

答案 1 :(得分:2)

是的,这是返回对常量对象的引用的正确方法。

但是,在收到返回引用的test函数中,左侧不是引用。这意味着您实际上将在此函数中创建整个地图的副本。一个简单的更改将解决该问题,然后test函数变为零拷贝:

void test()
{
    map< string, vector<string> > const & m = obj.get();
    // and then print
}

答案 2 :(得分:1)

这是正确的,但您应该使用引用来存储obj.get()的结果,如前所述。如果你做了这样的事情,这将是不正确的:

const map< string, vector<string> >& foo()
{
    map< string, vector<string> > m;
    // ...
    return m;
}

因为在这种情况下,m完成执行后foo()将不再存在。

答案 3 :(得分:0)

让我向您展示一个非常简单的示例,而不是直接回答您的问题。考虑一个简单的类A,其中有一个double作为其私有成员。

class A{

private:

  double a;

public:

  A(double _a);

  double
  get_a();

  double&
  get_aref();

  const double&
  get_aconstref();

};

该类的实现。非常简单

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;
}

现在让我们进入使用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;
}

所以你只能做一个 const double& aconstref = ainst.get_aconstref();
而不是 double& aconstref = ainst.get_aconstref();
如果类的方法以const T&amp;形式返回类型T的类成员之一,则意味着它不希望调用者更改该成员。在上面的例子中,T是双精度数。在nits位置替换std :: map并保持相同的逻辑。我希望这很有说服力。如果删除两个注释行,编译器会抱怨,因为您正在尝试更改该引用。