C++中结构体属性秒变数组元素:高效访问技巧揭秘

文摘   2024-12-16 13:05   江苏  

C++中结构体属性秒变数组元素:高效访问技巧揭秘

如何将结构体的属性当作数组元素访问?

在C++中,我们可能会用一个由多个字符串组成的类或结构体来表示一个URL,如下所示:

struct basic {
    std::string protocol;
    std::string username;
    std::string password;
    std::string hostname;
    std::string port;
    std::string pathname;
    std::string search;
    std::string hash;
};

为了将每个组件与一个索引关联起来,我们可以使用一个enum class

enum class component {
    PROTOCOL = 0,
    USERNAME = 1,
    PASSWORD = 2,
    HOSTNAME = 3,
    PORT = 4,
    PATHNAME  = 5,
    SEARCH = 6,
    HASH = 7,
};

最初,你可能会使用switch语句来访问组件:

std::string& get_component(basic& url, component comp) {
    switch (comp) {
        case component::PROTOCOL: return url.protocol;
        case component::USERNAME: return url.username;
        case component::PASSWORD: return url.password;
        case component::HOSTNAME: return url.hostname;
        case component::PORT:     return url.port;
        case component::PATHNAME: return url.pathname;
        case component::SEARCH:   return url.search;
        case component::HASH:     return url.hash;
    }
}

如果频繁访问,switch case可能会引入性能开销。为了更好的性能,我们可以将组件存储在一个数组中:

struct fat {
    std::array<:string> data;, 8>
    std::string &protocol = data[0];
    std::string &username = data[1];
    std::string &password = data[2];
    std::string &hostname  = data[3];
    std::string &port  = data[4];
    std::string &pathname = data[5];
    std::string &search = data[6];
    std::string &hash = data[7];
};

或者,你可以避免硬编码索引:

struct fat {
    std::array<:string> data;, 8>
    std::string& protocol  = data[int(Component::PROTOCOL)];
    std::string& username  = data[int(Component::USERNAME)];
    std::string& password  = data[int(Component::PASSWORD)];
    std::string& hostname  = data[int(Component::HOSTNAME)];
    std::string& port      = data[int(Component::PORT)];
    std::string& pathname  = data[int(Component::PATHNAME)];
    std::string& search    = data[int(Component::SEARCH)];
    std::string& hash      = data[int(Component::HASH)];
};

有了这个新的数据结构,通过索引获取组件变得更简单:

std::string& get_component(fat& url, component comp) {
    return url.data[int(comp)];
};

不幸的是,每个引用在新的fat数据结构中可能在64位系统上占用8字节。如果你不经常创建数据结构的实例,这不是问题。但如果你需要频繁创建实例,你可能想要避免使用引用。你可以尝试用简单的方法替换引用:

struct advanced {
    std::array<:string> data;, 8>
    std::string &protocol() { return data[0]; }
    std::string &username() { return data[1]; }
    std::string &password() { return data[2]; }
    std::string &hostname() { return data[3]; }
    std::string &port() { return data[4]; }
    std::string &pathname() { return data[5]; }
    std::string &search() { return data[6]; }
    std::string &hash() { return data[7]; }
};

这并不完全令人满意,因为它需要调用方法而不是访问属性。Eugene Ostroukhov有一个更好的方法,使用指向成员的指针操作符。我们创建一个编译时数组,包含指向basic结构体属性的指针:

std::string& get_component_fast(basic& url, component comp) {
    constexpr static std::array accessors = {&basic::protocol,
      &basic::username, &basic::password, &basic::hostname,
      &basic::port, &basic::port, &basic::pathname,
      &basic::search, &basic::hash};
    return url.*accessors[int(comp)];
}

这样,你就不需要修改原始类,而且很可能获得极好的性能。

编程悟道
自制软件研发、软件商店,全栈,ARTS 、架构,模型,原生系统,后端(Node、React)以及跨平台技术(Flutter、RN).vue.js react.js next.js express koa hapi uniapp Astro
 最新文章