我有一个Maybe
类,它是一个基于堆栈的类,可能包含给定的类型。我们有某些函数返回包含mutable或const引用的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
{1}})如果我写这个,那不是问题。
Maybe<T&>
在一位同事偶然发现这个问题之后,我有一个明智的想法是在可能返回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&
如果没有,它会调用&&
版本,这是不好的,因为这会返回一个引用。
我考虑将const&&
版本设为const&&
版本以避免重复;然而,我需要复制,而不是移动内部值。而且我不太了解const_cast
的语义,知道内部const&&
是否可以接受,或者当我改变auto
时,这会导致疯狂和歇斯底里。如果我不必,我不必写这个功能的两个副本。
在这种情况下,什么是正常的最佳做法?我需要编写所有4个函数吗?或者我可以用3来轻松逃脱?
有没有更好的方法来避免这种悬空参考问题?这只是一个问题,因为Maybe
通常会删除引用,因此您不会意外地引用临时引用,但因为auto
的类型已经是一个普通值,所以#&} 39;只是包装一个参考类型,就可以用脚射击自己了。只是说&#34;那么在那种情况下不要使用{{1}},&#34;这是非常诱人的,但它仍然很容易意外搞砸,而且我很难做错事。
答案 0 :(得分:2)
无论如何,你都无法获得良好代码的const&&
。
唯一的方法是
const T
的函数。 (无论如何,拥有这样的回归类型是一个坏主意。)const T&&
的函数。 (DITO)const&&
。 (无论如何你都不会这样做。)&&
的隐式转换。 (这不会发生,因为你有一个超载接受r值参考。)因此,如果您想要对API进行防弹,那么正确的方法只是delete
- 过载:
Maybe<Val &> maybe(Key const& key) const&& = delete;
答案 1 :(得分:0)
我认为这不是一个真正的问题。考虑一下程序
#include <map>
#include <cstdio>
int main() {
int& x = std::map<int, int>{{3, 4}}[3];
printf("%d\n", x);
}
在地图被销毁之后,引用x
将悬空(使最后一行未定义行为)。标准库没有阻止这种情况。
我也从未听说过有人意外犯过这种错误。
使用您的地图,情况相同。
IMO,根据地图的值类别返回Maybe<Val>
或Maybe<Val&>
太混乱了。每次在临时对象上调用.maybe
时,请三思而后行。