2

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

一般来说,在这些选项中,以这种方式使用联合的内存效率更高?

我在这里寻找解决原则的答案:也就是说,联合的主要目的是节省内存。

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

代码块 (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;
    }
};

(注意:代码背后的想法是任何员工都是小时工或薪水,因此这里是工会。请不要为这个问题提出不涉及工会的替代解决方案。我不担心解决特定问题,我对工会感兴趣。)


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

C++ 标准规定 int、long 类型的大小是多少?

C++ 指针使用多少内存?

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

4

2 回答 2

3

规则#1:跟随你的分析器(它会告诉你哪个对你的程序更有效)

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

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

我知道我“不允许”提出替代方案:(住在 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 } 
    };
}
于 2013-10-26T20:23:55.877 回答
1

B可能会使用最少的内存,但 50 是一个不错的选择,因为它让人怀疑。

使用 A,大概您将对两种可能性之一进行单独的内存分配。在内存使用方面,这几乎总是会引入一些低效率,加上指针本身的空间,所以它输给了 B。不过,在两个信息结构的大小差异更大的特殊情况下,它可能会获胜与指针的大小相比,超过一定比例使用较小的结构,并且您从诸如池分配器之类的极低开销的内存分配器中分配它们。

使用 CI 假设您的意思是 50 的数组char,而不是 50string或的数组cstring。我相信 name 的平均长度加上 的开销string小于 50 个字符,这就是我说 B 优于 C 的基础。但是,你是正确的,开销string取决于一些实现细节,所以这个我不能一概而论。此外,如果您要与名字都略低于 50 个字符的人打交道,那么 C 会赢。我只是认为这不太可能。

当然,C 更受限制,因为它根本无法处理名称超过 50 个字符的人(如果存储以 nul 结尾的字符串,则为 49 个字符)。

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

  • 8 个字节用于起始指针
  • 结束指针 8 个字节
  • 8字节容量
  • 用于包含字符串数据的分配标头的另外两个指针(16 字节),分配本身向上舍入为 8 或 16 字节。

短字符串总共需要 48 或 56 个字节(尽管有一种叫做“短字符串优化”的东西可以让短字符串变得更好,尽管根据细节它可能会使长字符串变得更糟)。通过这种实现string和内存分配,C 将获胜,即使没有四舍五入,它也可能在斯里兰卡获胜。

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

于 2013-10-26T20:22:43.683 回答