推断 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 左值引用
它返回一个引用/常量引用。如果你的vector
是const
,它返回一个常量引用,否则它返回一个引用。见:std::vector<T, Allocator>::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
成员函数中,向量v
是const
。它是back()
成员函数返回std::vector<T>::const_reference
。如果向量不是const
,则返回类型将为std::vector<T>::reference
。
在这种情况下,这两种类型等效于const T&
和T&
,但是vector
的适当包装器还可以允许向量使用的分配器,并且返回类型可能不是那么简单。使用template <class T, class Alloc> wrapper ... std::vector<T, Alloc> v; ...
,分配器Alloc
可以提供自己的引用类型;为了匹配这些类型,正确的名称来自 std::vector
中的 typedef。
【讨论】:
back() 不返回迭代器。它确实返回了对 T 的引用。我不明白第二部分。完美的返回类型扣除将是 decltype(auto) (如另一个答案所述)。 @phön — 哎呀,愚蠢的错字。那应该是reference
。固定。以上是关于推断 std::vector::back() 的返回类型的主要内容,如果未能解决你的问题,请参考以下文章
std::vector.push_back() 的奇怪(记忆?)问题
没有匹配函数调用‘std::vector::push_back(std::string&)’