2

以下の 3 つのコード ブロック、文字列/共用体の競合に対する 3 つの代替ソリューションを検討してください。

これらのオプションのうち、一般に、この方法での共用体の使用に関してメモリ効率が高いのはどれですか?

ここで原則に対処する答えを探しています。つまり、ユニオンの主な目的はメモリを節約することです。

編集:クラスの割り当てにより、この方法でユニオンを使用する必要がありました。どれが最も効率的かを考えさせられ、それが私がここにたどり着いた方法です。

コードブロック (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 が別のテイクを必要とする場合を除きます (これは非常に珍しいことです)。

代替案を提案することは「許可されていない」ことを知っています: ( 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 } 
    };
}
于 2013-10-26T20:23:55.877 に答える
1

B はメモリの使用量が最も少ないと思われますが、50 を選ぶのは適切な数字でした。

A では、おそらく 2 つの可能性のいずれかの個別のメモリ割り当てを行うことになります。メモリの使用に関しては、ほとんどの場合、これはある程度の非効率性をもたらします。さらに、ポインタ自体のためのスペースがあるため、B に負ける可能性があります。ただし、2 つの情報構造体のサイズがさらに異なる特殊なケースでは、勝つ可能性があります。ポインターのサイズよりも小さいサイズの構造体を一定の割合以上で使用し、プール アロケーターなどの非常にオーバーヘッドの少ないメモリ アロケーターからそれらを割り当てます。

CIでは、50またはcharの配列ではなく、 50 の配列を意味すると仮定します。名前の平均の長さに のオーバーヘッドを加えたものは 50 文字未満であり、それが B が C に勝ると私が言う根拠だと思います。ただし、 のオーバーヘッドはいくつかの実装の詳細に依存することは正しいので、これは一概には言えません。さらに、名前がすべて 50 文字をわずかに下回る人を相手にしている場合は、C が勝ちます。それはありそうもないことだと思います。stringcstringstringstring

もちろん、C は、名前が 50 文字 (NUL で終わる文字列を格納する場合は 49 文字) を超える名前を持つ人をまったく処理できないという点で、より制限されています。

[編集: もう一度考えてみると、文字列のオーバーヘッドは次のようになります。

  • 開始ポインタ用に 8 バイト
  • 終了ポインタの場合は 8 バイト
  • 容量は8バイト
  • 文字列データを含む割り当てのヘッダー用のさらに 2 つのポインター (16 バイト)。割り当て自体は 8 または 16 バイトに切り上げられます。

短い文字列の合計で 48 または 56 バイト (ただし、短い文字列を改善する「短い文字列の最適化」と呼ばれるものがありますが、詳細によっては長い文字列を悪化させる可能性があります)。その実装stringとメモリ割り当てにより、C が勝つでしょう。また、切り上げを行わなくても、スリランカでは C が勝つ可能性があります。

したがって、実際のメモリ使用量を測定する方法を検討する価値があります。]

于 2013-10-26T20:22:43.683 に答える