【问题标题】:Why my const ref becomes invalid?为什么我的 const ref 变得无效?
【发布时间】:2016-07-14 03:42:02
【问题描述】:

为什么我的 const ref 在这段代码中变得无效以及如何避免这种情况?我无法复制,这是我的应用程序的瓶颈。

class Foo {
public:
    const std::string& string() const {
        return string;
    }

private:
    std::string string = "asdf";
};

Foo foo;
std::vector<std::pair<const std::string&, int>> invalid;
for (int i = 0; i < 5; i++) {
    invalid.emplace_back(std::make_pair(foo.string(), i);
    // after this line invalid[i].first is invalid
}

【问题讨论】:

  • 模板参数推导的工作方式是make_pair 在您的调用中返回std::pair&lt;std::string, int&gt;;然后 emplace 构造 std::pair&lt;const std::string&amp;, int&gt; 。所以引用绑定到临时对的成员,而不是foo.string。让它invalid.emplace_back(std::pair&lt;const std::string&amp;, int&gt;(foo.string(), i));
  • 你怎么知道invalid[i].first无效? Foo 不能使用移动构造函数赋值。这对于矢量元素是否合法? (真正的问题 - 我还没有完全赶上 C++11。)如果您使用 std::pair&lt;const std::string*, int&gt; 作为元素类型,它是否有效?
  • @IgorTandetnik - 把它作为一个答案,这样我就可以投票了!
  • invalid.emplace_back(foo.string(), i)。构造对是多余的,而且你也做错了。
  • 在发布之前测试您的代码。

标签: c++ reference invalidation


【解决方案1】:

Igor Tandetnik 已经在您的代码中指出了问题。 FWIW,我认为在任何情况下让容器通过引用来引用其他对象的成员都不是一个好主意——隐含地依赖于对象的相对提升时间。您可以考虑使用shared_ptr to const string,如下所示:

#include <string>
#include <memory>
#include <vector>                                                                                                                           
class Foo {
public:
    const std::shared_ptr<const std::string> string() const {
        return _string;
    }   

private:
    std::shared_ptr<std::string> _string = std::make_shared<std::string>("asdf");
};  

int main()
{   
    Foo foo;
    std::vector<std::pair<std::shared_ptr<const std::string>, int>> invalid;
    for (int i = 0; i < 5; i++) {
        invalid.emplace_back(std::make_pair(foo.string(), i));
    }   
}   

【讨论】:

    【解决方案2】:

    make_pair 返回的是 pair&lt;std::string,int&gt;,而不是 pair&lt;const std::string&amp;, int&gt;,因为标准要求它是这样的。

    template <class T1, class T2>
    constexpr pair<V1, V2> make_pair(T1&& x, T2&& y);
    

    § 20.3.3 - 8

    返回:pair&lt;V1, V2&gt;(std::forward&lt;T1&gt;(x), std::forward&lt;T2&gt;(y));

    其中V1V2 确定如下: 让每个Ti 的Ui 为decay_t&lt;Ti&gt;。那么每个 Vi 都是 X& 如果 Ui 等于 reference_wrapper,否则 Vi 是 Ui。

    这应该按照标准工作:

    invalid.emplace_back(std::make_pair(std::ref(foo.string()), i));
    

    根据我的说法:

    invalid.emplace_back(decltype(invalid)::value_type(foo.string(), i));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-09
      • 1970-01-01
      • 2013-03-20
      • 2016-12-18
      • 2019-10-26
      • 2021-05-02
      • 1970-01-01
      相关资源
      最近更新 更多