如何在没有编译器警告的情况下返回对空字符串的 const 引用?

Posted

技术标签:

【中文标题】如何在没有编译器警告的情况下返回对空字符串的 const 引用?【英文标题】:How can I return a const reference to an empty string without a compiler warning? 【发布时间】: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,在此过程中创建一个临时对象。返回对该临时对象的引用,就像它超出范围并被销毁一样。 【参考方案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;。另外,它改变了调用者的界面,所以我不太喜欢这个主意。

以上是关于如何在没有编译器警告的情况下返回对空字符串的 const 引用?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不接收空字符串的情况下获取主板 ID?

如何在没有警告的情况下使用 execv()?

如何在没有任何错误或警告的情况下找到构建失败的原因

在 PHP 5.3 中,如何在没有严格警告的情况下在一行中获取单个元素数组中的值

为啥在一种情况下会收到带有字符串文字的不推荐使用的转换警告,而在另一种情况下却没有?

如何在我自己的代码中使用 Visual C++ 在不运行静态代码分析的情况下导致 SAL 编译器警告