【问题标题】:boost::optional<> in a union?boost::optional<> 在联合中?
【发布时间】:2011-06-08 02:51:01
【问题描述】:

我有一个可选的 POD 结构,它将包含在联合中。
boost::optional&lt;&gt; 按值保存其类型,所以我认为这可行:

union helper
{
    int foo;
    struct 
    {
        char basic_info;
        struct details {
            //...
        };

        boost::optional<details> extended_info;
    } bar;
    //  ...
};

helper x = make_bar();

if( x.bar.extended_info )
{
    // use x.bar.extended_info->elements
}

但是 VS2008 抱怨我的 bar 结构现在 had a copy constructor 由于 boost::optional&lt;details&gt; 元素。

作为替代,我添加了一个布尔标志来指示可选参数是否有效,但它很笨重:

union helper
{
    int foo;
    struct 
    {
        char basic;
        struct details {
            bool valid;
            //...
        } extended;
    } bar;
    //  ...
};

我考虑实现 details::operator bool() 以返回 details::valid 变量,但这很模糊,而且对人类不利。
boost::optional&lt;&gt; 清楚地记录了语法和意图,不需要进行侦探工作。

最后,helper union 需要是 POD,所以我不能做任何动态分配 - 否则我会使用指针。

对于语法上类似于 boost::optional&lt;&gt; 的东西有什么建议可以在联合中使用吗?

【问题讨论】:

  • 为什么不能使用指针?允许动态分配 POD;它只是没有自动初始化。还是您的 helper 联合需要考虑您的 bar 结构的大小?
  • union是按值复制的,作为字节发送给另一个进程,所以不能共享内存。
  • 将非 POD 类型转换为字节是未定义的行为。您必须使用 POD 类型进行二进制序列化。实际上,现在大多数不使用二进制通信协议,而是使用基于 XML 的通信协议。
  • 你是对的。不幸的是,这是一个遗留产品,不能轻易更改。我一口一口地吃这头大象。

标签: c++ boost optional-variables


【解决方案1】:

正如其他人所提到的,理想的做法是从union 更改为boost::variant&lt;&gt;

但是,如果这不可能,您可以实现boost::optional&lt;&gt; 的 POD 近似值,如下所示:

实施

template <typename T>
class Optional
{
    T value;
    bool valid;

public:

    // for the if(var) test
    operator bool() const  {  return valid;  }

    //  for assigning a value
    Optional<T> &operator=(T rhs)   
    {  
        value = rhs;  
        valid = true;  
        return *this;  
    }

    //  for assigning "empty"
    Optional<T> &operator=(void *)  
    {  
        valid = false;  
        return *this;  
    }

    // non-const accessors
    T &operator*()   {  return  value;  }
    T *operator->()  {  return &value;  }

    // const accessors
    const T &operator*()  const  {  return  value;  }
    const T *operator->() const  {  return &value;  }
};

如果您持有 Optional&lt;&gt; 的 const 实例,则 const 访问器是必需的。

用法

像指针一样,Optional&lt;T&gt; 没有默认状态,必须先初始化才能依赖它(无论是否为空)。
boost::optional&lt;T&gt; 不同,Optional&lt;T&gt; 不能从其T 值类型构造,而只能从另一个Optional&lt;T&gt; 构造。
如果您真的想在构造时对其进行值或空初始化,您可以使用operator Optional&lt;T&gt;() 创建一个辅助类。我选择不这样做。

建筑

Optional<details> additional_info;
Optional<details> more_info(additional_info);

作业

// if there's no additional info
additional_info = 0;

// if there is extended info
details x;
//  ...populate x...
additional_info = x;

数据访问

if( extended_info )
{
    extended_info->member;
    // - or -
    details &info = *extended_info;
}

所以 - 结果并没有太糟糕。它不会让我感到很温暖和模糊,但它可以完成工作。

【讨论】:

    【解决方案2】:

    您不能将非 POD 类型用作联合中的字段。在 C++ 中使用 boost::variant 或类似的东西而不是联合。保留 union 只是为了与用 C 编写的模块兼容。

    【讨论】:

    • 差不多 - 使用 boost::variant。
    • 我有很多将联合序列化为字节的遗留代码。我现在想避免这种重构。
    • 您必须使用您为序列化描述的“笨重”帮助器,并将可选的变体与它转换。非 POD 对象的内存布局可能会被编译器的下一个版本/服务包/编译选项优化,无关。
    • mskfisher,看看 boost:apply_vistor。我在我的代码中使用它来序列化 boost 变体。
    猜你喜欢
    • 2018-02-28
    • 1970-01-01
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    • 2014-11-21
    • 2015-12-01
    • 2014-04-09
    • 1970-01-01
    相关资源
    最近更新 更多