【问题标题】:Further rvalue references and temporary objects更多的右值引用和临时对象
【发布时间】:2013-12-15 11:06:34
【问题描述】:

在详细说明我之前的questionquestion 时,我想了解在这个真实场景中发生了什么。我有以下模板函数:

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(const Key& key, const Value& value)
{
    Insert(std::make_pair(key, value));
}

例如,使用左值和右值的混合调用,就像在这个调用中一样:

std::string name = "The Great";
hashTable.Insert(name, "Gatsby");

(用于测试目的)。 Insert以上调用

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(pair<const Key, Value>&& keyValuePair)
{
    if (buckets.size() == 0)
    {
        buckets.resize(1);
    }

    HashFunction hash;
    unsigned long hashValue = hash(keyValuePair.first) % buckets.size();
    buckets[hashValue].push_back(std::move(keyValuePair));
}

几个问题:

1. 由于通过引用传递,我希望其中一个元素是文字字符串的一对是未定义的行为。是这样吗?

2. 当我进入make_pair 行时,代码首先调用make_pair(_Ty1&amp;&amp; _Val1, _Ty2&amp;&amp; _Val2),因此编译器似乎将keyvalue 解释为右值。为什么?

3. 进入第二个Insert 方法之前的下一个调用是pair(pair&lt;_Other1, _Other2&gt;&amp;&amp; _Right)。无论第二个Insert 采用&amp;&amp; 还是const &amp;,都会发生这种情况。这里发生了什么?

4. 与最后一个相关联,考虑到它的作用,第二个 Insert 应该采用 const pair&amp; 还是 pair&amp;&amp;

更新:看了Scott Meyer关于通用引用的优秀视频,阅读了模板推导和引用折叠规则,在你的帮助下我可以回答1、2和4。但我还是看不懂为什么在Insert 调用之前调用pair 的移动构造函数。有什么帮助吗?

【问题讨论】:

  • hashTable 的类型是什么?
  • 一个 FastHash。我猜散列类型和相等类型并不重要。
  • 字符串文字具有静态存储持续时间。
  • _Ty1&amp;&amp; 是所谓的通用参考。在这种模式_Ty&amp;&amp; 中,_Ty1 可以推导出为左值引用(通过特殊规则,如果参数是左值)。如果推断它是对some_type 的左值引用,则应用引用折叠并将some_type&amp; &amp;&amp; 折叠为some_type&amp; - 参数变为左值引用。

标签: c++ c++11 undefined-behavior move-semantics rvalue-reference


【解决方案1】:

进入第二个插入方法之前的下一个调用是pair(pair&lt;_Other1, _Other2&gt;&amp;&amp; _Right)。无论第二个插入采用&amp;&amp; 还是const &amp;,都会发生这种情况。这是怎么回事?

那是 std::pair 的转换构造函数:它将您传递的对 - std::make_pair(key, value) - 从 std::pair&lt;Key, Value&gt; 转换为第二个 Insert 函数的参数类型 std::pair&lt;const Key, Value&gt;。如果您自己指定对类型而不是让std::make_pair 推断它,则可以避免转换:

Insert(std::pair<const Key, Value>{key, value});

当然,这是将参数复制到 pair 中,在 C++11 中,我们有一个经验法则,即如果要复制某些内容,则应按值接受它。所以也许将这个Insert 实现为:

template <typename Key, typename Value, typename HashFunction, typename Equals>
void FastHash<Key, Value, HashFunction, Equals>::Insert(Key key, Value value)
{
    Insert(std::pair<const Key, Value>{std::move(key), std::move(value)});
}

【讨论】:

  • 就是这样!不错的答案。我不明白的是:“在 C++11 中,我们有一个经验法则,如果你要复制一些东西,你应该按价值接受它。”为什么?我可以在哪里阅读更多相关信息?
  • @KristianD'Amato 简而言之,按值接受会在调用者传递左值时生成副本,并在调用者传递右值时移入参数。这是两全其美的。你应该阅读 Dave Abrahams Want Speed? Pass by Value.
猜你喜欢
  • 2011-02-14
  • 1970-01-01
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多