这里是否误报:警告C4172:返回局部变量或临时变量的地址?

问题描述 投票:0回答:2

在以下代码中:

#include <execution>
#include <vector>

template<typename T> 
class Index {
public:    
    const std::string& text;
    const std::vector<T>& index;

    decltype(index.begin())& begin() { return index.begin(); } // No warning
    decltype(index.end())&   end()   { return index.end(); }  // No warning

    const decltype(index.cbegin())& begin() const { return index.cbegin(); }
    const decltype(index.cend())&   end() const { return index.cend(); }
};

int main()
{
}

Visual Studio 2022(最新版本)给出警告:

警告 C4172:返回局部变量或临时变量的地址

每行

两次

decltype
。同时具有相同配置的godbolt则不然。

这是误报警告还是应该修复代码?

我在代码中的意图是返回 const 迭代器的 const 引用。这是正确的方法/语法吗?

更新

有趣的是,对于非常量版本(刚刚添加到上面的源代码中),没有一个编译器给出警告,尽管我们仍然对本地副本有相同的引用。

更新2

我意识到实际上我确实需要这两位新成员,而我唯一需要的是:

template<typename T> 
class Index {
public:    
    const std::string& text;
    const std::vector<T>& index;

    decltype(index.begin()) begin() const { return index.begin(); }
    decltype(index.end())   end()   const { return index.end(); }  

};

这涵盖了客户端代码中的所有需求。所以,我很幸运地尝试将

const
作为带有引用的返回值类型;结果我收到了这个警告,并在该线程的所有参与者的帮助下理解了它。

c++ compiler-warnings temporary-objects reference-binding
2个回答
2
投票

这不是误报,如果您实例化类模板,您可以在 Compiler Explorer 上重现它:

template class Index<int>;

MSVC 向您提供已发布的警告,GCC 向您提供

<source>:10:72: warning: returning reference to temporary [-Wreturn-local-addr]
   10 |     const decltype(index.cbegin())& begin() const { return index.cbegin(); }
      |                                                            ~~~~~~~~~~~~^~

问题是

index.cbegin()
按值返回迭代器,而不是按引用返回。 返回类型为
const std::vector::const_iterator&
,并且此
const&
绑定到临时
const_iterator
对象。

性能注意事项

你说过你要通过

const&
返回迭代器,因为

迭代器大小足够大而产生影响时的性能考虑。

这不是您应该担心的事情。 迭代器是指针的泛化([iterator.requirements.general] p1),并且是小型、轻量级的对象,可以廉价地按值传递。 如果迭代器的传递成本很高,那就是迭代器的设计问题。

请注意,

<algorithm>
中的标准库算法也按值获取迭代器。

关于语言演化的注释

如果 P2748: Disallow Binding a Returned Glvalue to a Temporary 被 C++26 标准接受(并且总体共识是有利的),那么你的代码将是格式错误的。

换句话说,它甚至可能无法在 C++26 中编译。


1
投票

您不是通过引用返回您所拥有的内容,而是返回函数调用的结果。

该函数恰好位于您引用的方法上是无关紧要的。

const std::vector<T>& index;


const decltype(index.cbegin())& begin() const { return index.cbegin(); }

解决方案是不返回引用——只返回副本。迭代器的复制成本应该很低。

© www.soinside.com 2019 - 2024. All rights reserved.