【问题标题】:How can I return a const reference to an empty string without a compiler warning?如何在没有编译器警告的情况下返回对空字符串的 const 引用?
【发布时间】:2015-05-14 13:56:40
【问题描述】:

我有一个 std::unordered_map<int, std::string> 和一个函数 GetString(int key),它接受一个 int 键并从此映射返回一个字符串值。

当在地图中找不到键时,我必须返回一个空字符串。

#include <iostream>
#include <string>
#include <unordered_map>

std::unordered_map<int, std::string> map
{
    { 5, "somelongstring" }
};

const std::string& GetString(int key)
{
    auto iterator = map.find(key);
    if (iterator == map.end())
    {
        return "";
    }

    return iterator->second;
}

int main()
{
    std::cout << GetString(1) << std::endl;
}

问题是编译器给了我这个警告

warning C4172: returning address of local variable or temporary

(使用 MS Visual Studio 2013)或

warning: returning reference to temporary [-Wreturn-local-addr]

(使用 g++ 4.9.2)

我发现摆脱这种情况的一种方法是在顶部声明 static const std::string 并返回它而不是空字符串文字

static const std::string Empty = "";

const std::string& GetString(int key)
{
    auto iterator = map.find(key);
    if (iterator == map.end())
    {
        return Empty;
    }

    return iterator->second;
}

但是定义一个空字符串字面量似乎不是很干净。有没有一种巧妙的方法来做到这一点?

更新:我的地图在启动期间被初始化一次,然后从多个线程同时读取(使用GetString)。使用函数静态空字符串不起作用,因为函数静态变量在 Visual Studio 的编译器下没有以线程安全的方式初始化。

【问题讨论】:

  • 我认为std::unordered_map 与您的问题没有任何关系,真的。
  • const 字符串在函数中可以是静态的,而不是全局的。
  • 我认为没有更好的解决方案。您需要一个 string 实例,该实例在您返回引用时仍然有效,或者您自己返回一个 string 实例(不是引用),但这可能效率低下。
  • @einpoklum 文字是const char[1] 类型,要返回对std::string 的引用,会创建一个临时文件,但您不能(合法)返回对临时文件的引用。跨度>
  • @einpoklum 字面量不是 std::string。这是一个C字符串。要从此函数返回它,必须将其转换为std::string,在此过程中创建一个临时对象。返回对该临时对象的引用,就像它超出范围并被销毁一样。

标签: c++ string


【解决方案1】:

警告消息明确说明了问题所在:您正在返回一个局部变量 (""") 的地址,该变量将在函数返回后从堆栈中释放。返回 std::string 会很好,因为您将在函数局部变量之外构造一个新字符串,但是当您返回 std::string&amp; 时,您确实使用了局部变量。

但是当您返回一个静态值时,只需将其设为静态即可:

const std::string& GetString(int key)
{
    static const string empty = "";
    auto iterator = map.find(key);
    if (iterator == map.end())
    {
        return empty;
    }

    return iterator->second;
}

【讨论】:

  • Afaik,函数静态变量在 Visual Studio 的编译器下没有以线程安全的方式初始化,尽管 c++ 11 标准要求这样做
  • @tcb 你是对的。通过您的编辑,我现在认为,除非您可以确保该函数至少会被调用一次(例如在地图初始化之后),否则 global 静态常量是最好的方法。
  • C++11 "magic statics" 现在也被 Visual Studio 2015 编译器支持 - blogs.msdn.microsoft.com/vcblog/2015/06/19/…
【解决方案2】:

我会将返回类型更改为std::string(因此返回空字符串是可以的)或std::string *(返回nullptr 表示未找到)。

否则编译器是对的:你不能返回对即将被销毁的本地对象的引用

【讨论】:

  • 返回 std::string 不是一个选项,因为我的地图包含巨大的字符串,我不想制作任何副本。我正在考虑返回一个指针,但如果可能的话,我想避免使用指针。
  • 如果您返回一个指针,那么也可以考虑将其设为 const std::string*,因为 OP 也返回了 const std::string&amp;。另外,它改变了调用者的界面,所以我不太喜欢这个主意。
猜你喜欢
  • 2015-09-24
  • 2018-01-29
  • 2017-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-20
相关资源
最近更新 更多