4

stlコンテナ(ベクトル)にデータがあります。ベクトルの各ノードは、stl文字列も含む構造体です。

struct record
{
string name;
string location;
int salary;
}

vector< record > employees;

従業員をシリアル化したいが、シリアル化する前に暗号化したい。

私の暗号化関数は次のようになります。

Encode(const char * inBfr, const int in_size, char ** outBfr, int& out_size )

検索すると、stl標準では構造体のメモリが連続している必要がないため、employees変数のメモリを取得することはできません。stlベースの構造/コンテナでこのエンコーディング関数を使用できる他のスマートな方法はありますか?Encode関数がプレーンなchar*バッファーで機能するのは良いことです。そのため、何が出入りするかは正確にわかりますが、stl構造はそうではなく、この関数でstlを使用できるように良い方法を見つけようとしています。

それが助けになるなら、私は他のstlコンテナを使うことにも門戸を開いています。

4

2 に答える 2

12

の要素はstd::vector<T>連続して配置されることが保証されていますが、これは実際には役に立ちません。レコードにはパディングが含まれている可能性があり、さらに重要なことstd::stringに、オブジェクトの外部にのコンテンツが格納されstd::stringます(小さな文字列の最適化が使用すると、値は内部に埋め込まれる可能性がありstd::stringますが、s値の一部ではない数バイトも含まれstd::stringます)。したがって、最良のオプションは、レコードをフォーマットし、フォーマットされた文字列を暗号化することです。

書式設定は簡単ですが、個人的にはstd::streambuf、暗号化をフィルタリングストリームバッファーで実行できるように、エンコード関数を単純なものにカプセル化します。あなたが与えた署名を考えると、これは次のようになります。

class encryptbuf
    : public std::streambuf {
    std::streambuf* d_sbuf;
    char            d_buffer[1024];
public:
    encryptbuf(std::streambuf* sbuf)
        : d_sbuf(sbuf) {
        this->setp(this->d_buffer, this->d_buffer + sizeof(this->d_buffer) - 1);
    }
    int overflow(int c) {
        if (c != std::char_traits<char>::eof()) {
            *this->pptr() = std::char_traits<char>::to_char_type(c);
            this->pbump(1);
        }
        return this->pubsync()? std::char_traits<char>::eof(): std::char_traits<char>::not_eof(c);
    }
    int sync() {
        char* out(0);
        int   size(0);
        Encode(this->pbase(), this->pptr() - this->pbase(), &out, size);
        this->d_sbuf->sputn(out, size);
        delete[] out; // dunno: it seems the output buffer is allocated but how?
        this->setp(this->pbase(), this->epptr());
        return this->d_sbuf->pubsync();
    }
};

int main() {
    encryptbuf    sbuf(std::cout.rdbuf());
    std::ostream eout(&sbuf);
    eout << "print something encoded to standard output\n" << std::flush;
}

これで、に印刷するだけでレコードの出力演算子をstd::ostream作成して、エンコードされたものを作成できます。

于 2012-10-03T21:59:11.710 に答える
6

構造を文字列にシリアル化してから、文字列を暗号化するのがおそらく最も簡単です。例えば:

std::ostringstream buffer;

buffer << a_record.name << "\n" << a_record.location << "\n" << a_record.salary;

encode(buffer.str().c_str(), buffer.str().length(), /* ... */);

もしそれが私なら、encodeおそらくベクトル、文字列、またはストリームで入力を受け取る(そしておそらく出力を生成する)ように書く(または少なくともそのラッパー)でしょう。

野心的になりたいのなら、他の可能性があります。まず第一に、@ MooingDuckはoperator<<、個々のアイテムを常に操作するのではなく、クラスのためにオーバーロードする価値があるという良い点を提起します。これは通常、上記のような小さな関数になります。

std::ostream &operator<<(std::ostream &os, record const &r) { 
    return os << r.name << "\n" << r.location << "\n" << r.salary;
}

これを使用すると、次のようになります。

std::ostringstream os;
os << a_record;

encode(os.str().c_str(), os.str().length(), /* ... */);

次に、非常に野心的なものにしたい場合は、暗号化を(たとえば)codecvtファセットに入れることができます。これにより、ストリームに書き込むときにすべてのデータを自動的に暗号化し、読み戻すときに復号化できます。もう1つの可能性は、streambuf代わりに暗号化をフィルタリングオブジェクトに組み込むことです。codecvtファセットはおそらく理論的には好ましい方法ですが、関係streambufのない「もの」があまり含まれていないため、ほぼ確実に実装が簡単です。

于 2012-10-03T21:14:44.980 に答える