2009-06-25 11 views
31

私は、DLLの境界を越えて文字列にデータを埋め込む方法を探していました。異なるコンパイラを使用しているため、すべてのdllインタフェースは単純なchar *です。std :: string内部バッファに直接書き込む

dll関数にポインタを渡して文字列バッファを直接満たすことができる方法はありますか?

string stringToFillIn(100, '\0'); 
FunctionInDLL(stringToFillIn.c_str(), stringToFillIn.size()); // definitely WRONG! 
FunctionInDLL(const_cast<char*>(stringToFillIn.data()), stringToFillIn.size()); // WRONG? 
FunctionInDLL(&stringToFillIn[0], stringToFillIn.size());  // WRONG? 
stringToFillIn.resize(strlen(stringToFillIn.c_str())); 

最も有望に見える一つは& stringToFillInです[0]が、それはあなたがその文字列を思うだろうことを考えると、これを行うには正しい方法です::データ()== &文字列[0]?それは矛盾しているようです。

それとも、余分な割り当てを飲み込むと、質問を避けた方が良いです:

vector<char> vectorToFillIn(100); 
FunctionInDLL(&vectorToFillIn[0], vectorToFillIn.size()); 
string dllGaveUs(&vectorToFillIn[0]); 

答えて

23

std::stringのデータがchar*として保存されていることが標準で保証されているかどうかはわかりません。私は考えることができる最もポータブルな方法は、メモリの連続チャンクにデータを格納することが保証されてstd::vectorを、使用することです:

std::vector<char> buffer(100); 
FunctionInDLL(&buffer[0], buffer.size()); 
std::string stringToFillIn(&buffer[0]); 

は、これはもちろんです二回コピーするデータを、必要ビット効率が悪い。

+5

、あなたはバッファとしてのstd ::ベクトルを使用して起動した場合ベクトルの各要素が1つずつ初期化される、異なる種類のパフォーマンス問題に遭遇します。 32Kのバッファを確保しておくと、このバッファを初期化するのにかなりのCPU時間を費やすことになります。連続したメモリのチャンクが必要な場合は、単に配列new char []をstd :: unique_ptrや他のRAIIパターンと組み合わせて使用​​する方がはるかに優れています。あなたが絶対に各要素を初期化する必要がある場合を除きます。 –

+2

http://stackoverflow.com/questions/11149665/c-vector-that-doesnt-initialize-its-membersのvector トリックを使用してください。 –

+0

"標準では' std :: string'のデータが 'char *'として格納されていることを保証していません。 "それは保証されています。 'std :: string'は' char'を使います。 http://en.cppreference.com/w/cpp/string/basic_string – cambunctious

3

私がのstd ::文字列を作成し、DLLの境界を越えて内部バッファへのポインタを出荷していないと思います。代わりに、単純なcharバッファ(静的または動的に割り当てられたバッファ)を使用します。 DLLの呼び出しが返った後、私はstd :: stringに結果を引き継ぐようにします。 calleesが内部クラスバッファに書き込むことを直感的に間違って感じるだけです。

0

std :: stringの標準部分はAPIであり、動作の一部であり、実装のメモリレイアウトではありません。

異なるコンパイラを使用している場合、それらが同じであると想定できない場合は、実際のデータを移送する必要があります。他の人がcharを移送し、新しいstd :: stringにプッシュすると言っています。

20

さらに多くの読書と掘り下げの後、私は文字列:: c_strとstring :: dataが文字列自体の格納方法とは関係のないバッファへのポインタを正当に返すことを発見しました。たとえば、文字列がセグメントに格納されている可能性があります。これらのバッファに書き込むことは、文字列の内容に未定義の影響を与えます。

さらに、string :: operator []は、一連の文字へのポインタを取得するために使用すべきではありません。単一の文字に対してのみ使用する必要があります。これは、ポインタ/配列の等価性が文字列で保持されないためです。

これは非常に危険ですが、これはいくつかの実装では動作しますが、突然将来何らかの理由で突然破損することがあります。

したがって、これを行う唯一の安全な方法は、文字列バッファに直接書き込む試みを避け、ベクトルを使用し、最初の要素へのポインタを渡して、ベクトルから文字列を割り当てますdll関数から戻ってきます。

+27

C++ 0xは連続したメモリを使用するように文字列を変更しています – Patrick

+2

パトリックが言っていること。また、2008年のHerb Sutter氏はC++ 0xワーキンググループとの議論の中で、連続していない実装については知らなかった:http://herbsutter.wordpress.com/2008/04/07/cringe-not-vectorsは連続することが保証されています/(そしてコメントまでスクロールダウン)。 –

+0

興味深いことに、&str [0]は連続したデータを与えなければならないとStroustrupは "The C++ Programming Language Special Edition" 20.3.3 p585でそうでないと言います。たぶん私はそれを誤解します。混乱をきれいにするためにC++ 0xにロールしてください!私たちは、コードのさまざまな部分で技術的に保証されていない動作に頼っていると思うので、ストリングについての私たちの仮定がもはや成り立たなければ、いくつかのテストを追加します。一息。 – markh44

0

あなたはすでに隣接性の問題に取り組んでいます(つまり、隣接していることは保証されていません)ので、割り当て/割り当て解除ポイントについて言及します。私は過去にdllのメモリを割り当てたところで(dllの外側にある)破壊時にエラーを引き起こしたdllを返すという問題がありました。これを修正するには、アロケータとメモリプールがdllの境界を超えて一貫していることを確認する必要があります。)デバッグ時間を節約できます;)

2

パトリックのコメントを考えてみると、std :: stringに直接書くのは大丈夫で便利です。私はこのMEX例のように、char *を取得するために&s.front()を使用します。

#include "mex.h" 
#include <string> 
void mexFunction(
    int nlhs, 
    mxArray *plhs[], 
    int nrhs, 
    const mxArray *prhs[] 
) 
{ 
    std::string ret; 
    int len = (int)mxGetN(prhs[0]); 
    ret.reserve(len+1); 
    mxGetString(prhs[0],&ret.front(),len+1); 
    mexPrintf(ret.c_str()); 
} 
+1

'string.front()'は空の文字列では呼び出されません。代わりに '&string [0]'を使用してください。 –

9

C++ 98では、あなたはstring::c_str()string::data()によって返されたバッファを変更しないでください。また、他の回答で説明したように、string::operator[]を使用して一連の文字へのポインタを取得することは避けてください。文字は1文字にしか使用できません。

C++ 11以降、文字列は連続したメモリを使用するため、&string[0]を使用して内部バッファにアクセスできます。

3

は限りC++ 11は、生産の練習では、連続したメモリの保証をを与えるように、この「ハック」メソッドは非常に人気があります:

効率の面では
std::string stringToFillIn(100, 0); 
FunctionInDLL(stringToFillIn.data(), stringToFillIn.size()); 
+0

編集のためにオリオンエドワーズに感謝します。 C++ 17標準のみに適用されることに注意してください。詳細はhttp://en.cppreference.com/w/cpp/string/basic_string/dataを参照してください。 –

関連する問題