c++ - Ref 限定的成员函数设计打破了 const 右值

标签 c++ c++11 reference

我有一个Maybe class 是可能包含给定类型的基于堆栈的类。我们有某些函数返回 Maybe包含可变或常量引用。这主要是为了减少样板文件、查找和不需要的拷贝。

Map<String, Foo> map;

// Normal C++
auto it = map.find("foo");
if (it != map.end())
  doStuff(*it);

// Has an extra lookup, bad
if (map.contains("foo"))
  doStuff(map.get("foo"));

// Uses Maybe
if (auto val = map.maybe("foo"))
  doStuff(*val);

// Also possible:
// apply calls the function with *this as argument if this is valid
map.maybe("foo").apply(&doStuff);

但是,当 map 时,这是有问题的是临时的:

Map<String, Foo> map;
Map<String, Foo> getMap() { return map; } // Returns a copy of map

if (auto val = getMap().maybe("foo")) // Returns Maybe<Foo&> to temporary
  doStuff(*val); // Very bad, *val has already been deleted

另一方面,因为Maybe<Foo>可从 Maybe<Foo&> 构造(一般来说, Maybe<T2> 可以从 Maybe<T> 构造,如果 T2 可以从 T 构造)那么如果我写这个,这不是问题。

if (Maybe<Foo> val = getMap().maybe("foo"))
  doStuff(*val); // OK, val contains a copy

在一位同事偶然发现这个问题后,我想到了一个好主意,在可能返回 Maybe<T&> 的地方使用 ref 限定的成员函数。返回 Maybe<T>相反,如果它是右值。

Maybe<Val> Map<Key, Val>::maybe(Key const& key) &&;
Maybe<Val const&> Map<Key, Val>::maybe(Key const& key) const&;
Maybe<Val &> Map<Key, Val>::maybe(Key const& key) &;

但是我在弄清楚在 const&&; 的情况下该怎么做时遇到了一些困难

如果没有,它将调用 const&版本,这很糟糕,因为这会返回一个引用。

我考虑制作 &&版本a const&&版本以避免重复;但是,那么我需要复制而不是移动内部值。而且我对 const&& 的语义理解不够了解 const_cast 是否可以接受在内部,或者当我变异 const&& 时这会导致疯狂和歇斯底里。如果不需要的话,我宁愿不必编写该函数的两个拷贝。

在这种情况下,正常的最佳实践是什么?我需要编写全部 4 个函数吗?或者我可以理智地摆脱 3 吗?

是否有更好的方法来避免这种悬空引用问题?这只是一个问题,因为 auto通常会删除引用,因此您不会意外地引用临时对象,但因为 Maybe 的类型已经是一个普通值,它只是包装了一个引用类型,这就有可能搬起石头砸自己的脚。只是说“那么在这种情况下不要使用 auto”是非常诱人的,但仍然很容易不小心搞砸,而且我宁愿很难做错事。

最佳答案

无论如何,你不可能在好的代码中得到 const&&

唯一的方法是

  1. 调用返回const T的函数。 (无论如何,拥有这样的返回类型都是一个坏主意。)
  2. 调用返回 const T&& 的函数。 (迪托。)
  3. 故意转换为 const&&。 (无论如何你都不会这样做。)
  4. 来自 && 的隐式转换。 (这不会发生,因为你有一个接受右值引用的重载。)

因此,如果您想要让 API 防弹,正确的方法就是删除该重载:

Maybe<Val &> maybe(Key const& key) const&& = delete;

关于c++ - Ref 限定的成员函数设计打破了 const 右值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27973279/

相关文章:

c++ - push_back 一个字符从一个字符串到另一个字符串

JSON Jackson 共享引用

javascript - 如何克隆数组中的对象项?

c++ - 函数引用站点

c++ - 为什么 getchar_unlocked() 比其他方法更快?

c++ - array_view.synchronize_asynch 会等待 parallel_for_each 完成吗?

c++ - 使用 Win32 线程模型时,MinGW-w64 是否支持开箱即用的 std::thread?

C++ 非静态数据成员初始化器,只是有点困惑

c++ - 什么是模板演绎指南,我们应该在什么时候使用它们?

c++ - 如何删除 BST 的所有节点以便在 C++ 中重用