2

私はいくつかのレガシーコードに取り組んでおり、cppファイルにいくつかの変更を加える必要があります.cppファイルにはextern "c"ブロックにコード全体が含まれています-

char* を返す関数を更新しました。コードは以下の func1() のようになります。私は std::strring と stringstream を使用しているので、extern ブロックの前に sstream と string ヘッダー ファイルを含めました。以下の関数は、c ファイルと cpp ファイルの両方から呼び出されます。したがって、ここで std::string を返すことはできません -

char* func1(someStruct* pt){
    std::strig nam = somefunc(pt);
    //have to append some integer in particular format
    std::stringstream ss;
    ss<<nam<<pt->int1 ......;

    nam = ss.str(); 
    //More code here for returning char* based on queries - (a)
}

この関数が呼び出される場所の 1 つで -

void otherFunc(.....){
    //......
    char* x = func(myptr);
    if(based_on_some_condition){
        char* temp = func3(x); //returns a char* to dynamically allocated array.
        strcpy(x,temp);       //copying (b)

    }
    //..........
}

以下は私のクエリです
-1)(a)で、次の2つの形式でchar *を返すことができます.(b)でコピーしても未定義の動作が発生しないように決定する必要があります-

i)Create a char array dynamically with size = nam.length()+10 (extra 10 for some work happening in func3).<br>
    char* rtvalue = (char*)calloc(sizeof(char),nam.length()+10);
    strcpy(rtvalue,nam.c_str());
    return rtvalue;
    And free(temp); in otherFunc() after strcpy(x,temp);

ii) Declare 'nam' as static std::string nam;
    and simply return const_cast<char*>(nam.c_str());
    Will defining 'nam' with static scope ensure that a correct return happen from function (ie no dangling pointer at 'x')?
    More importantly, can I do this without worrying about modification happening at (b).

どちらがより良い解決策ですか?

4

2 に答える 2

1

問題は を返すことchar *です。C++ を使用する場合は、この型を使用しないでください。これは C ではありません。std::stringまたはstd::vector<char>使用する必要があります。

この種の関数で戻り値の型として使用するchar *と、未定義の動作 (解放されたメモリへのアクセス) またはメモリ リークで終了します。

関数を使用static std::string nam;すると内部状態が維持され、これは常にトラブルにつながります。たとえば、スレッド機能を作成すると、未定義の動作が発生します。さらに悪いことに、何らかの理由でこの関数を 2 回使用すると、2 回目の呼び出しの結果が最初の呼び出しの結果に影響を与えます (たとえば、同僚は非表示の副作用を予期しないため、この関数を使用します)。

C コードからアクセスできる API を設計している場合は、この API を別の方法で設計する必要があります。あなたが提供している機能の種類がわかりません。おそらく、次のようなものにする必要があります。

char *func1(someStruct* pt, char *result, int size){ // good name could be like this: appendStructDescription
    std::strig nam = somefunc(pt);
    //have to append some integer in particular format
    std::stringstream ss;
    ss<<nam<<pt->int1 ......;

    nam = ss.str(); 

    int resultSize = std::min(size - 1, nam.length());
    memcpy(result, nam.c_str(), resultSize);
    result[resultSize] = 0;
    return result + resultSize;
}

このアプローチには大きな利点があります。メモリ管理の責任は呼び出し元にあり、API のユーザーは何が期待されているかを理解しています。

于 2018-06-08T17:54:34.657 に答える