【问题标题】:Return reference to a primitive parameter返回对原始参数的引用
【发布时间】:2017-03-13 15:25:22
【问题描述】:

我有这样的功能

template<typename T>
const T& get(std::string key, T defaultValue)
{
    try {
        return getFromMap<T>(key);
    }
    catch (const std::exception &e)
    {
        return defaultValue;
    }
}

它从混合类型映射中检索类型化的值,如果找不到键,则返回 defaultValue。映射中有原始类型和对象类型作为值(因此我们必须返回对该值的引用)。我们只需要担心原始的 defaultValues;不支持将它与我们的对象值一起使用。此函数在 linux 上运行良好,但是在 Windows 上运行时,我返回的 defaultValues 是垃圾。例如,

get("missing", true) 返回 false(即 0)

get("missing", 3.14) 返回 0

get("missing", "myDefault") 返回垃圾地址

等等。我猜这个问题类似于 defaultValue 被复制到函数内部的一个新变量中,然后返回对临时的引用。如何修复我的功能以在 Windows 上执行正确的操作?

【问题讨论】:

  • 你可以按值返回。复制省略将使其最佳化。
  • 如果你只有“原始值”(我假设像intdouble),那么总是按值传递和返回。根本不需要参考。
  • 经验法则:永远不要返回对非静态局部变量或非引用函数参数的引用。
  • 获取前去掉'&'

标签: c++ templates reference


【解决方案1】:

首先,无论操作系统如何,您的功能都会损坏。原因是当异常情况发生时它具有未定义的行为:您正在返回对函数本地对象的引用(参数defaultValue)。一旦函数退出,这样的引用就会变得悬空,通过悬空引用访问对象是 UB。它碰巧在 Linux 上工作只是运气不好,而且很容易通过更改编译器版本、编译开关、源代码的其他部分或几乎其他任何东西来破坏它。

恐怕您面临的问题没有既快速又干净的解决方案。

我认为最好提供两种get 重载,一种用于按值返回的原始类型,另一种用于按const T &amp; 返回的非原始类型(不支持默认值,你提到的对你来说没问题)。你可以这样做:

template<typename T, typename = std::enable_if_t<std::is_fundamental<T>::value>>
T get(const std::string &key, T defaultValue)
{
    try {
        return getFromMap<T>(key);
    }
    catch (const std::exception &e)
    {
        return defaultValue;
    }
}

template<typename T, typename = std::enable_if_t<!std::is_fundamental<T>::value>>
const T& get(const std::string &key)
{
    return getFromMap<T>(key);
}

请注意,我将get 更改为通过const&amp; 获取其key 参数。如果您担心性能,则不应复制 key 只是为了从中读取。

【讨论】:

    猜你喜欢
    • 2019-02-26
    • 1970-01-01
    • 2021-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多