【问题标题】:Pass const Key_Type& to operator[] of std::map将 const Key_Type& 传递给 std::map 的 operator[]
【发布时间】:2014-07-28 07:28:08
【问题描述】:

为什么我不能将const Key_Type& 传递给 std::map 的 operator[]?我已经这样做了,它编译但在运行时std::bad_alloc 抛出异常:

std::map<std::string, int> myMap;

const std::string& f(const std::string& groupA, const std::string& groupB) 
{ 
    return groupA > groupB ? groupA + groupB : groupB + groupA;
}

std::cout << myMap[f("a", "b")];

【问题讨论】:

  • 想一想:你如何引用表达式(如groupA + groupB)?

标签: c++ map std


【解决方案1】:

您正在返回对函数 const std::string&amp; f(const std::string&amp; groupA, const std::string&amp; groupB) 中的临时对象的引用

return groupA > groupB ? groupA + groupB : groupB + groupA;

+ 运算符返回一个临时值,然后通过引用返回该值。

因此更改返回类型 return by value (const std::string) 解决了这个问题。

正如@Narek 所指出的,Herb Sutter 如何解释使用 const ref 来处理临时变量。但我们的问题陈述与 Sutter 讨论的不符。为了解释更多,我创建了一个小程序。该程序解释了问题和解决方法:

#include <iostream>
#include <map>

/*
std::map<std::string, int> myMap;

const std::string& f(const std::string& groupA, const std::string& groupB) 
{ 
    return groupA > groupB ? groupA + groupB : groupB + groupA;
}*/


struct X{

  int member;


  X():member(0){
      std::cout<<"X ctr "<<std::endl;
  }

  X(const X& rhs){

      std::cout<<"X copy ctr "<<std::endl;
  }

  ~X(){

      std::cout<<"X dtr"<<std::endl;
      member = -1;
  }
};

void f2(const X& obj){

    std::cout<<"func "<<obj.member<<std::endl;

}   

const X& f3(){ 
    return X(); 
}

X f4(){ 
    return X(); //ideally not a good idea, exception is
    //http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
}

int main()
{
    /*  myMap["ba"] = 1;
    std::cout <<"key "<< f("a", "b")<<std::endl;
    std::cout << myMap[f("a", "b")]<<std::endl;*/

    std::cout << "-----Faulty Case-----------"<<std::endl;

    //reference returned by f3 is local to f3 call and 
    //is destructed as soon as f3() is out of stack
    //and hence the reference in f2() is not valid
    f2( f3() );

    std::cout <<std::endl<< "-----Correct way-----------"<<std::endl;

    //A temporary object is returned by f4 which is then referred by reference in f2.
    //This reference is alive in stack of f2 and hence can be used inside 
    //f2 with valid results.
    //As explained in following article, the refernce should remain
    //alive in stack to use temporary objects.
    //http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
    f2( f4() );

    //note in previous expression, f4 returns by value but still copy ctr is not invoked,
    //this I believe is Return Value Optimization (might be compiler dependent)

    return 0;
}

这个程序的输出:

main.cpp: In function �const X& f3()�:
main.cpp:41:14: warning: returning reference to temporary [-Wreturn-local-addr]
     return X(); 
              ^

Executing the program....
$demo 
-----Faulty Case-----------
X ctr 
X dtr
func -1

-----Correct way-----------
X ctr 
func 0
X dtr

我希望这可以清除乌云。

【讨论】:

  • 但是当我通过将函数返回的临时引用分配给const Key_Type&amp;来使用临时对象时,应该延长临时对象的寿命,对吗? herbsutter.com/2008/01/01/….
  • 作为KEY的函数返回的值只是用来从map中获取VALUE,所以你不必担心生活。如果您想存储持久性,请将其存储在命名变量中。
  • 如果不是引用返回的临时值的存在,那是什么问题?
  • 在您现有的解决方案中,您正在返回对一旦 func 调用返回时超出范围的值的引用。
  • @Narek 在绑定到函数返回值的情况下,生命周期不会延长
【解决方案2】:

将 f 的定义从 const std::string&amp; f 更改为 const std::string f 解决了这个问题,因为这样 (A + B) 的临时结果会复制到返回变量中。否则会返回一个指向临时变量的指针,分配的内存的所有权是不明确的,事情就会出错。

【讨论】:

  • 是的,确实如此。其实我也做了同样的事情来删除异常,但是我不明白为什么我有一个异常。
  • 提问或澄清应在 cmets 中完成。答案应说明问题,最好给出问题和解决方案背后的原因。
  • @JoachimPileborg 我猜他会编辑他的真实答案。
猜你喜欢
  • 2015-09-17
  • 1970-01-01
  • 1970-01-01
  • 2017-02-27
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 2012-10-20
  • 1970-01-01
相关资源
最近更新 更多