简体   繁体   中英

Use of union in a command data structure

I am working on a project in which we pass commands to lower layer from upper layer.

1. Handle Single command at a time

we use following data structure.

struct Command{
     //Different command types==> SEND / CREATE_TRANSACTION etc.
     CommandType type;

     //Associated parameters with every command
     union{
         struct{
             string remote_ip;
             uint16_t remote_port;
         }address;

         struct{
             string transaction_id;
             string transaction_details;
         }tsx;
         .
         .
         .
     }params;
};

We pass different parameters for different commands. Union makes it memory efficient.

Is there any better way (or a design pattern) to do it in C++?

Another one.

2. Handle multiple commands in a single command object.

I can do it in this way:

struct Command{
    uint64_t flag; //ORed value of different command types 

    //parameters
    struct{
        string remote_ip;
        uint16_t remote_port;
    }address;

    struct{
        string transaction_id;
        string transaction details;
    }tsx;
};

But, it is not memory efficient.

Is there any better way to create multiple commands in a single object (in C++)?

You want std::variant or boost::variant . Variants are type-safe discriminated unions.

struct address {
    string remote_ip;
    uint16_t remote_port;
};

struct tsx {
    string transaction_id;
    string transaction details;
};

using command = std::variant<address, tsx>;

Example usage:

command c0{tsx{/* ... */}};
std::visit(
    overload(
        [](const address&){ /* handle address case */ },
        [](const tsx&)    { /* handle tsx case */ }
    ),
    c0
);

In order to learn how to implement overload and similar pattern-matching utilities, refer to my ACCU 2017 talk: "Implementing variant Visitation Using Lambdas"

You could use std::variant and a visitor pattern. Depending on the command type your visitor would react differently to process the payload data.

http://en.cppreference.com/w/cpp/utility/variant/visit

This provides type safety that unions do not offer

Using unions as "variants", particularly for the purpose of "saving memory", is almost always an indication of poor design. You need to question the if design/specification makes sense. So yes, there are much better ways:

If these 2 structs have nothing to do with each other, then keep them as 2 separate structs (or classes). Designing programs without tight coupling is vastly more important than saving 10-20 bytes of memory.

Otherwise, if these 2 structs do have something in common, make "params" an abstract base class that contains whatever the structs have in common. Then have "address" and "tsx" inherit that base class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM