4

多くのRAIIサンプルクラスがファイルハンドルをラップしているのがわかります。

私はこれらの例を運がなくても文字ポインタに適合させようとしました。

私が使用しているライブラリには、文字ポインタのアドレスを受け取る関数があります(get_me_a_string(char ** x)のように宣言されています)。これらの関数は、その文字ポインタにメモリを割り当て、ライブラリのエンドユーザーに任せて、独自のコードでクリーンアップします。

だから、私はこのようなコードを持っています...

char* a = NULL;
char* b = NULL;
char* c = NULL;

get_me_a_string(&a);
if(a == NULL){
    return;
}


get_me_a_beer(&b);
if(b == NULL){
    if(a != NULL){
        free(a);
    }
    return;
}


get_me_something(&c);
if(c == NULL){
    if(a != NULL){
        free(a);
    }
    if(b != NULL){
        free(b);
    }
    return;
}

if(a != NULL){
    free(a);
}
if(b != NULL){
    free(b);
}
if(a != NULL){
    free(b);
}

RAIIは私が上で持っているこの混乱の答えであるように思えます。誰かがFILE*ではなくchar*をラップする単純なC++クラスを提供できますか?

ありがとう

4

8 に答える 8

5

標準ライブラリにはすでに利用可能なものがあります。それはと呼ばれstd::stringます。

編集:新しい情報に照らして:

メモリを割り当てていっぱいにします。内容を新しいstd::stringオブジェクトにコピーすることはできますが、それでも関数によって割り当てられたメモリを解放する必要があります。

これは、実装者側の設計が不十分です。割り当てを行うモジュールが割り当て解除を担当する必要があります。

boost::shared_ptrさて、これでシステムからそれを取得したので、を解放するために使用できます。

template<typename T>
struct free_functor
{
    void operator() (T* ptr)
    {
        free(ptr);
        ptr=NULL;            
    }
};
shared_ptr<X> px(&x, free_functor());
于 2010-02-02T19:34:53.820 に答える
2

非常に基本的な実装(コピー不可などにする必要があります)。

struct CharWrapper {
    char* str;
    CharWrapper(): str() {}  // Initialize NULL
    ~CharWrapper() { free(str); }
    // Conversions to be usable with C functions
    operator char**() { return &str; }
    operator char*() { return str; }
};

適切な初期化はコンストラクターよりも後で行われるため、これは技術的にはRAIIではありませんが、クリーンアップは処理されます。

于 2010-02-02T19:34:29.017 に答える
1

あなたはこのようなことを試すことができます:

template <typename T>
class AutoDeleteArray
{
public:
    explicit AutoDeleteArray(const T* ptr)
        : ptr_(ptr)
    {}
    ~AutoDeleteArray()
    {
        delete [] ptr_;
        // if needed use free instead
        // free(ptr_);
    }

private:
    T *ptr_;
};

// and then you can use it like:
{
    char* a = NULL;

    get_me_a_string(&a);
    if(a == NULL)
      return;

    AutoDeleteArray<char> auto_delete_a(a);
}

これは最も信頼できるソリューションではありませんが、目的には十分である可能性があります。

PS:std::tr1::shared_ptrカスタムデリッターでも機能するのだろうか?

于 2010-02-02T19:46:47.330 に答える
0

Boostは使用できないと言っているので、リソースを共有または転送しない非常に単純なスマートポインターを作成することはそれほど難しくありません。

これが基本的なことです。テンプレートパラメータとしてデリータファンクタを指定できます。私は変換演算子が特に好きではないので、代わりにget()メソッドを使用してください。

release()やreset()などの他のメソッドを自由に追加できます。

#include <cstdio>
#include <cstring>
#include <cstdlib>

struct Free_er
{
    void operator()(char* p) const { free(p); }
};

template <class T, class Deleter>
class UniquePointer
{
    T* ptr;
    UniquePointer(const UniquePointer&);
    UniquePointer& operator=(const UniquePointer&);
public:
    explicit UniquePointer(T* p = 0): ptr(p) {}
    ~UniquePointer() { Deleter()(ptr); }
    T* get() const { return ptr; }
    T** address() { return &ptr; } //it is risky to give out this, but oh well...
};

void stupid_fun(char** s)
{
    *s = static_cast<char*>(std::malloc(100));
}

int main()
{
    UniquePointer<char, Free_er> my_string;
    stupid_fun(my_string.address());
    std::strcpy(my_string.get(), "Hello world");
    std::puts(my_string.get());
}
于 2010-02-02T21:30:59.887 に答える
0

プレーンstd::stringを使用するか、ローカル配列の場合はboost :: scoped_arrayを使用し、共有文字列の場合はboost :: shared_arrayを使用します(後者を使用すると、呼び出すカスタム削除機能を提供できますfree())。

于 2010-02-02T19:38:43.277 に答える
0

auto_ptrはあなたが望むものだと思います

または、auto_ptrセマンティクスが機能しない場合は、shared_ptrをブーストします。

于 2010-02-02T19:35:03.957 に答える
0

回答ありがとうございます。

残念ながら、このプロジェクトでブーストや他のライブラリを使用することはできません...そのため、これらの提案はすべて役に立ちません。

ここのようなCでの例外処理のようなものを見てきました... http://www.halfbakery.com/idea/C_20exception_20handling_20macros

そして、C++ に Java のように finally がない理由を調べたところ、この RAII に出くわしました。

デストラクタの方法でコードを C++ のみにするか、C 例外マクロ (恐ろしい goto:) を使用するかはまだわかりません。

Tronic は次のような提案をしました。RAII、または一般的なデストラクタでは、それらはセグメンテーション フォールトに対応しているはずですか? 私はそうではないと思います。

私が気に入らない唯一の点は、printf ステートメントでキャスト (char*) を使用する必要があることです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct CharWrapper {
    char* str;
    CharWrapper(): str() {}  // Initialize NULL
    ~CharWrapper() {
        printf("%d auto-freed\n", str);
        free(str);
    }
    // Conversions to be usable with C functions
    operator char*()  { return  str; }
    operator char**() { return &str; }
};

// a crappy library function that relies
// on the caller to free the memory
int get_a_str(char **x){
    *x = (char*)malloc(80 * sizeof(char));
    strcpy(*x, "Hello there!");
    printf("%d allocated\n", *x);
    return 0;
}


int main(int argc, char *argv[]){
    CharWrapper cw;
    get_a_str(cw);
    if(argc > 1 && strcmp(argv[1], "segfault") == 0){
        // lets segfault
        int *bad_ptr = NULL;
        bad_ptr[8675309] = 8675309;
    }
    printf("the string is : '%s'\n", (char*)cw);
    return 0;
}
于 2010-02-02T20:29:20.103 に答える
0

別の解決策は次のようなものです。これは、このコードを C で記述する方法です。

char* a = NULL;
char* b = NULL;
char* c = NULL;

get_me_a_string(&a);
if (!a) {
    goto cleanup;
}

get_me_a_beer(&b);
if (!b) {
    goto cleanup;
}

get_me_something(&c);
if (!c) {
    goto cleanup;
}

/* ... */

cleanup:
/* free-ing a NULL pointer will not cause any issues
 * ( see C89-4.10.3.2 or C99-7.20.3.2)
 * but you can include those checks here as well
 * if you are so inclined */
free(a);
free(b);
free(c);
于 2010-02-02T20:56:04.613 に答える