推断 std::vector::back() 的返回类型

Posted

技术标签:

【中文标题】推断 std::vector::back() 的返回类型【英文标题】:Deducing return type of std::vector::back() 【发布时间】:2020-07-04 10:28:58 【问题描述】:

我知道标题有点含糊,但本质上,我想知道我们是否要为某些 STL 容器(即向量或列表)创建一个包装类,返回某些返回的方法的正确方法是什么对元素的引用。考虑以下代码:

template<typename T>
class wrapper

private:
std:vector<T> v;

public:
T back() const 
return v.back();


;

根据我的理解,back() 方法将返回一个对 vector 中最后一个对象的 const 左值引用,所以如果我们通过副本返回它会发生什么,我们会得到引用的副本还是目的?这是编译器可以作为返回值优化的一部分进行优化的东西吗?

【问题讨论】:

wrapper::back() 返回一个右值。您将获得 v 向量中最后一个元素的副本。 【参考方案1】:

要保留引用类型,请使用decltype(auto):

decltype(auto) back() const 
    return v.back();

【讨论】:

【参考方案2】:

返回某些返回元素引用的方法的正确方法是什么。

正确的方法取决于您的需求,即您是否需要副本或左值引用/常量左值引用。我个人建议返回 const 引用或引用。

vector::back() 方法将返回对向量中最后一个对象的 const 左值引用

它返回一个引用/常量引用。如果你的vectorconst,它返回一个常量引用,否则它返回一个引用。见:std::vector&lt;T, Allocator&gt;::back

如果我们通过副本返回它会发生什么,我们会得到引用或对象的副本

只会创建引用对象的副本。

这是编译器可以作为返回值优化的一部分进行优化的东西吗?

是的,来自copy elision 上的 cppreference:

这取决于您的类型 T 并且编译器不是必需来执行此操作的。来自copy elision上的cppreference:

在以下情况下,编译器是允许的,但不需要省略类对象的复制和移动(C++11 起)构造,即使复制/移动(C++11 起)构造函数和析构函数也是如此有明显的副作用。对象直接构建到存储中,否则它们将被复制/移动到。这是一种优化:即使它发生并且没有调用复制/移动(自 C++11 起)构造函数,它仍然必须存在且可访问(就好像根本没有发生任何优化一样),否则程序会出错 -形成:

在对象的初始化中,当源对象是无名临时对象并且与目标对象具有相同的类类型(忽略 cv 限定)时。当无名临时变量是 return 语句的操作数时,这种复制省略的变体称为 RVO,即“返回值优化”。

另外,如果你通过复制返回,T 的复制构造函数可能会抛出并且你可能有一个无效的对象。

【讨论】:

关于复制省略的最后一部分我不清楚。问题中return 语句中的操作数是左值,而不是纯右值。如果我们有类似 return T; 的内容,它将适用。 是的,你是对的。我的错。我会更新答案,这里可能会发生复制省略,但这不是强制性的。 这里不会发生复制省略。 back() 返回一个引用,然后我们从中创建一个副本并返回它。为了避免复制,我们必须在包装器中返回一个引用。 (虽然在 C++17 之前,可以创建一个附加副本,可以省略。但让我们谈谈现代 C++)【参考方案3】:

在问题中wrapper 类的const 成员函数中,向量vconst。它是back() 成员函数返回std::vector&lt;T&gt;::const_reference。如果向量不是const,则返回类型将为std::vector&lt;T&gt;::reference

在这种情况下,这两种类型等效于const T&amp;T&amp;,但是vector 的适当包装器还可以允许向量使用的分配器,并且返回类型可能不是那么简单。使用template &lt;class T, class Alloc&gt; wrapper ... std::vector&lt;T, Alloc&gt; v; ... ,分配器Alloc可以提供自己的引用类型;为了匹配这些类型,正确的名称来自 std::vector 中的 typedef。

【讨论】:

back() 不返回迭代器。它确实返回了对 T 的引用。我不明白第二部分。完美的返回类型扣除将是 decltype(auto) (如另一个答案所述)。 @phön — 哎呀,愚蠢的错字。那应该是reference。固定。

以上是关于推断 std::vector::back() 的返回类型的主要内容,如果未能解决你的问题,请参考以下文章

std::vector.push_back() 的奇怪(记忆?)问题

std::vector push_back 是瓶颈

std::vector pop_back() 实现

没有匹配函数调用‘std::vector::push_back(std::string&)’

正确使用用户定义类型的 std::vector.push_back()

想简化我的 std::vector push_back 使用