关于在C ++中使用联合的内存效率

时间:2013-10-26 19:57:54

标签: c++ pointers memory unions

考虑下面的三个代码块,三个字符串/联合冲突的替代解决方案。

在这些选项中,一般来说,哪种方式对于以这种方式使用联盟更有效?

我正在寻找解决原则的答案:也就是说,工会的主要目的是节省内存。

编辑:课堂作业迫使我以这种方式使用工会。它让我想到哪个是最有效的,这就是我到达这里的方式。

代码块(A):

// unions with pointers to structs
struct HourlyInfo {
    string firstName;
    string lastName;
    string title;
    int hoursWorked;
    double hourlyRate;
};

struct SalaryInfo {
    string firstName;
    string lastName;
    string title;
    double salary;
    double bonus;
};

struct Employee {
    bool isHourly;
    union {
        HourlyInfo *hourlyEmployee;
        SalaryInfo *salaryEmployee;
    }

};

代码块(B):

// applying unions to relevant and non-string data types
struct Employee {
    string firstName;
    string lastName;
    string title;
    bool isHourly;
    union {
        struct {
            double hourlyRate;
            int hoursWorked;
        } hourly;
        struct {
            double salary;
            double bonus;
        } salaried;
    };
};

代码块(C):

// use cstring instead of string
struct HourlyInfo {
    cstring firstName[50];
    cstring lastName[50];
    string title[50];
    int hoursWorked;
    double hourlyRate;
};

struct SalaryInfo {
    cstring firstName[50];
    cstring lastName[50];
    cstring title[50];
    double salary;
    double bonus;
};

struct Employee {
    bool isHourly;
    union {
        HourlyInfo hourlyEmployee;
        SalaryInfo salaryEmployee;
    }
};

(注意:代码背后的想法是,任何员工都是小时工资或工资,因此这里是工会。请不要建议不涉及工会的问题的替代解决方案。我不担心解决问题具体问题,我对工会感兴趣。)


此外,指针和其他数据类型的大小似乎差异很大:

What does the C++ standard state the size of int, long type to be?

How much memory does a C++ pointer use?

这是否意味着我们在这里没有关于内存效率的一揽子声明?如果是这样,我们应该在确定最有效的方法时考虑哪些因素?

2 个答案:

答案 0 :(得分:3)

规则#1:关注你的探查器(告诉你哪个你的程序更有效

规则#2:关于内存分配:使用自定义分配器来隐藏复杂性

规则#3:设计数据类型以明确表达意图/目的(在这个意义上,只有B是一个选项)。当然,除非规则#1需要另一次采取(这是非常不寻常的)

我知道我“不被允许”提出替代方案:( Live on Coliru

#include <string>
#include <boost/variant.hpp>

struct HourlyInfo {
    int    hoursWorked;
    double hourlyRate;
};

struct SalaryInfo {
    double salary;
    double bonus;
};

namespace detail {

    template <template <typename...> class Allocator = std::allocator>
    struct basic_employee {
        using string = std::basic_string<char, std::char_traits<char>, Allocator<char>>;
        string firstName;
        string lastName;
        string title;

        using RateInfo = boost::variant<HourlyInfo, SalaryInfo>;
        RateInfo rates;
    };
}

using Employee = detail::basic_employee<>; // or use a custom (pool?) allocator

int main()
{
    Employee staff1 = { 
        "John", "Cage", "From accounting", 
        SalaryInfo { 1900.00, 120.0 } 
    };
    Employee contractor = { 
        "Joe", "Duffy", "Plumbing jobs", 
        HourlyInfo { 3, 46.00 } 
    };
}

答案 1 :(得分:1)

B 可能可能使用最少的内存,但50是一个很好的数字,因为它让人怀疑。

使用A,大概是你要对两种可能性中的一种进行单独的内存分配。在内存使用方面,这几乎总会带来一些低效率,而且还有指针本身的空间,所以它输给了B.但是,在两种信息结构不同的特殊情况下,它可能会获胜。在大小上超过指针大小,超过一定比例使用较小的结构,并从凶猛的低开销内存分配器(如池分配器)中分配它们。

使用C我假设你的意思是50 char的数组,而不是50 stringcstring的数组。我认为名称的平均长度加上string的开销小于50个字符,这就是我说B击败C的基础。但是,你说的是正确的string的开销取决于一些实现细节,所以我不能断言。此外,如果你正在处理名字都不到50个字符的人,那么C就会赢。我认为这不太可能。

当然,C更受限制,因为它不能与名称超过50个字符的人交易(如果存储字符串为nul,则为49)。

[编辑:再考虑一下,字符串的开销可能是:

  • 8个字节用于启动指针
  • 结束指针的8个字节
  • 容量为8个字节
  • 包含字符串数据的分配标头的两个以上指针(16个字节),分配本身四舍五入为8或16个字节。

一个短字符串总共48或56个字节(虽然有一个名为&#34;短字符串优化&#34;这使短字符串更好,虽然取决于细节它可能使长字符串更糟)。通过string和内存分配的实现,C将获胜,即使没有四舍五入,它也可能在斯里兰卡获胜。

因此,值得研究如何衡量实际的内存使用情况。]