1

この質問は、C++ <-> C++ の相互運用性に関するものです。

よく知られているように、標準ライブラリのクラス/関数の実装は、ベンダーによって異なる場合があります。さらに、異なるコンパイラ キー、構成 (デバッグ/リリース) などを使用する場合、同じライブラリ ベンダー内でも実装が異なる場合があります。

そのため、多くのライブラリ開発者は古いプレーンな C スタイルの API に移行しています。これは、醜いエラーを起こしやすいインターフェイスにつながります。

たとえば、関数から文字列を取得するために、Win GetCurrentDirectory 関数のようなインターフェイスが使用されます。

DWORD WINAPI GetCurrentDirectory(
  __in   DWORD nBufferLength,
  __out  LPTSTR lpBuffer
);

単純な文字列を取得するためだけに、3 つのパラメーター + 両側のいくつかのボイラープレート コード (バッファー サイズが十分かどうかのチェックなど)。

すべての変換を自動的に行い、簡単に再利用できる補助アダプター/プロキシ クラスを使用することを考えています。

何かのようなもの:

#include <string>
#include <algorithm>
#include <iostream>
#include <ostream>

class StringConverter
{
    char *str; // TODO: use smart pointer with right deleter
public:
    StringConverter(const std::string &user_string) // Will be defined only at user side
    {
        str=new char[user_string.length()+1];
        (*(std::copy(user_string.begin(),user_string.end(),str)))=0;
    }
    operator std::string() // Will be defined only at library side
    {
        return std::string(str);
    }
    ~StringConverter()
    {
        delete [] str;
    }
};

StringConverter foo()
{
    return std::string("asd");
}


int main(int argc,char *argv[])
{
    std::cout << std::string(foo()) << std::endl;
    return 0;
}

http://ideone.com/EfcKv

なお、ユーザー文字列からStringConverterへの変換はユーザー側でのみ定義し、StringConverterからライブラリ文字列への変換はライブラリ内のみで定義する予定です。また、(右側のヒープから) 右側のデリータを使用する必要があります。

このようなアプローチについてどう思いますか?

大きな落とし穴はありますか?

優れた代替手段はありますか?

4

1 に答える 1

0

この手法は、標準のデータ型に互換性がない場合でも機能しますが、うまくいかない場合もあります。名前マングリングの違いとクラスメモリレイアウトの違い(vptrsとタグ)が思い浮かびます。

これがCAPIが好まれる理由です。

ただし、ライブラリの呼び出し元が表示する必要のないC APIを埋め込むことで、使いやすさを向上させることができます。次に、表示可能なライブラリインターフェイスを提供する薄い慣用的なC++オーバーレイを追加します。場合によっては、シンオーバーレイコードを呼び出し元側とライブラリ側の両方で使用でき、それぞれが独自の環境(フラグ、リンク規則など)でコンパイルされます。Cデータ型のみが交換されます。これらのデータ型が単純であるほど、より多くの互換性が得られます。

また、このレイヤーは、コードと同様に、オブジェクトごとにAPIの同じ側でメモリの割り当てと割り当て解除が行われるように注意します。しかし、それはより柔軟になる可能性があります。たとえば、呼び出し元で割り当てられたオブジェクトがライブラリで割り当て解除されるように調整したり、その逆を行うことができます。

// library.h for both caller and library

// "shadow" C API should not be used by caller
extern "C" {
void *make_message(char *text);
char *get_text_of_message(void* msg);
void send_message(void *msg); // destroys after send.
}

// Thin C++ overlay
class Message {
  void *msg;
public:

  Message(const std::string &text) {
    msg = make_message(text.c_str());
  }

  void send() {
    if (msg) send_message(msg);
    else error("already sent");
    msg = 0;
  }

  std:string getTextString() {
    return std:string(get_text_of_message(void* msg));
  }
}
于 2012-08-09T18:26:42.007 に答える