通过引用存储的c ++变体类成员 [英] c++ variant class member stored by reference

查看:105
本文介绍了通过引用存储的c ++变体类成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用std :: variant.我将std :: variant存储为类的成员.在下面的代码中,如果按值存储变量,则工作正常,但如果按引用存储变量,则工作不正常(对于矢量情况和自定义对象).为什么会这样?

I am trying to experiment with std::variant. I am storing an std::variant as a member of a class. In the below code, things work fine if the variant is stored by value, but does not work (for the vector case, and for custom objects too) if the variant is stored by reference. Why is that?

#include <variant>
#include <vector>
#include <iostream>


template<typename T>
using VectorOrSimple = std::variant<T, std::vector<T>>;


struct Print {
void operator()(int v) { std::cout << "type = int, value = " << v << "\n"; }
void operator()(std::vector<int> v) const { std::cout << "type = vector<int>, size = " << v.size() << "\n"; }
};


class A {
public:
    explicit A(const VectorOrSimple<int>& arg) : member(arg) {
        print();
    }

    inline void print() const {
        visit(Print{}, member);
    }

private:
    const VectorOrSimple<int> member;  // const VectorOrSimple<int>& member; => does not work
};


int main() {
    int simple = 1;
    A a1(simple);
    a1.print();

    std::vector<int> vector(3, 1);
    A a2(vector);
    a2.print();
}

请参见 http://melpon.org/wandbox/permlink/vhnkAnZhqgoYxU1H 版本,以及 http://melpon.org/wandbox/permlink/T5RCx0ImTLi4gk5e 以获得崩溃的版本出现错误:抛出'std :: bad_variant_access'实例后调用终止 what():意外索引"

See http://melpon.org/wandbox/permlink/vhnkAnZhqgoYxU1H for a working version, and http://melpon.org/wandbox/permlink/T5RCx0ImTLi4gk5e for a crashing version with error : "terminate called after throwing an instance of 'std::bad_variant_access' what(): Unexpected index"

奇怪的是,当编写以成员存储为引用的boost :: variant版本的代码时,它在gcc7.0中可以按预期工作(打印矢量大小= 3两次)(请参见此处 http ://melpon.org/wandbox/permlink/2GRf2y8RproD7XDM ).

Strangely, when writing a boost::variant version of the code with the member stored as a reference, it works as expected (prints vector size = 3 twice) with gcc7.0 (see here http://melpon.org/wandbox/permlink/eW3Bs1InG383vp6M) and does not work (prints vector size = 3 in constructor and then vector size = 0 on the subsequent print() call, but no crash) with clang 4.0 (see here http://melpon.org/wandbox/permlink/2GRf2y8RproD7XDM).

这很令人困惑.有人可以解释发生了什么吗? 谢谢.

This is quite confusing. Can someone explain what is going on? Thanks.

推荐答案

它不起作用,因为该语句A a1(simple);创建了一个临时变体对象!

It doesn't work because this statement A a1(simple); creates a temporary variant object!

然后,您将所述临时文件绑定到您的const参考.但是,在a1的构造结束后,该临时变量将立即超出范围,从而给您留下了一个悬而未决的参考.显然,创建副本是可行的,因为它总是涉及使用有效副本.

You then proceed to bind said temporary to your const reference. But the temporary goes out of scope immediately after the construction of a1 is over, leaving you with a dangling reference. Creating a copy works, obviously, since it always involves working with a valid copy.

一种可能的解决方案(如果始终复制的性能令您感到烦恼)是接受一个按变量值的变体对象,然后将其移动到本地副本中,就像这样:

A possible solution (if the performance of always copying worries you) is to accept a variant object by-value, and then move it into your local copy, like so:

explicit A(VectorOrSimple<int> arg) : member(std::move(arg)) {
    print();
}

这将允许您使用左值或右值调用构造函数.对于左值,将通过移动源变量的副本来初始化member,对于rvalues,将仅(最多)两次移动源内容.

This will allow your constructor to be called with either lvalues or rvalues. For lvalues your member will be initialized by moving a copy of the source variant, and for rvalues the contents of the source will just be moved (at most) twice.

这篇关于通过引用存储的c ++变体类成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆