web-dev-qa-db-ja.com

std :: string.c_str()を返す方法

定数のcharポインタを返すメソッドがあります。 _std::string_を使用し、最後にc_str() charポインタを返します。

_const char * returnCharPtr()
{
    std::string someString;

    // some processing!.

    return someString.c_str();
}
_

COVERITYツールから、上記は適切な使用法ではないとの報告を受けました。私はグーグルで調べたところ、someStringがその破壊に遭遇するとすぐに、charポインタが返されて無効になることがわかりました。

これを踏まえて、この問題をどのように修正しますか? charポインターを正確に返す方法は?

_std::string_を返すと、この問題は解決します。しかし、これを行う他の方法があるかどうかを知りたいです。

29
user3210526

このコードで何が起こるか:

const char * returnCharPtr()
{
    std::string someString("something");
    return someString.c_str();
}
  1. std::stringのインスタンスが作成されます-これは自動保存期間を持つオブジェクトです
  2. この文字列の内部メモリへのポインタが返されます
  3. オブジェクトsomeStringが破棄され、その内部メモリがクリーンアップされます
  4. この関数の呼び出し元はdangling pointer(invalid pointer)を受け取り、未定義の動作

最良の解決策:オブジェクトを返す

std::string returnString()
{
    std::string someString("something");
    return someString;
}
20
LihO

C++では、最も単純なことは_std::string_を返すことです(これはRVOやC++ 11移動セマンティクスなどの最適化により効率的でもあります)。

_std::string returnSomeString()
{
    std::string someString;

    // some processing...

    return someString;
}
_

生のC _char*_ポインタが本当に必要な場合は、戻り値に対していつでも.c_str()を呼び出すことができます。

_// void SomeLegacyFunction(const char * psz)

// .c_str() called on the returned string, to get the 'const char*' 
SomeLegacyFunction( returnSomeString().c_str() );
_

関数から_char*_ポインターを本当に返したい場合、動的にヒープに文字列メモリを割り当て(たとえば、_new[]_を使用)、そのポインターを返すことができます。

_// NOTE: The caller owns the returned pointer, 
// and must free the string using delete[] !!!
const char* returnSomeString()
{
    std::string someString;

    // some processing...

    // Dynamically allocate memory for the returned string
    char* ptr = new char[someString.size() + 1]; // +1 for terminating NUL

    // Copy source string in dynamically allocated string buffer
    strcpy(ptr, someString.c_str());

    // Return the pointer to the dynamically allocated buffer
    return ptr;
}
_

別の方法として、宛先バッファポインタandバッファサイズを(バッファオーバーランを回避するために!)関数パラメータとして指定します。

_void returnSomeString(char* destination, size_t destinationSize)
{
    std::string someString;

    // some processing...

    // Copy string to destination buffer.
    // Use some safe string copy function to avoid buffer overruns.
    strcpy_s(destination, destinationSize, someString.c_str());
}
_
12
Mr.C64

この質問にはCのフラグが付いているので、次のようにします。

_#define _POSIX_C_SOURCE 200809L
#include <string.h>

const char * returnCharPtr()
{
  std::string someString;

  // some processing!.

  return strdup(someString.c_str()); /* Dynamically create a copy on the heap. */
}
_

使用しなくなった場合に関数が返すfree()を忘れないでください。

6
alk

まあ、COVERITYは正しいです。現在のアプローチが失敗する理由は、関数内で作成したstd::stringのインスタンスは、その関数が実行されている間のみ有効であるためです。プログラムが関数のスコープを離れると、std :: stringのデストラクタが呼び出され、それが文字列の終わりになります。

しかし、Cストリングが必要な場合はどうでしょう...

const char * returnCharPtr()
{
    std::string someString;

    // some processing!.

    char * new_string = new char[someString.length() + 1];

    std::strcpy(new:string, someString.c_str());

    return new_string;
}

しかし、ちょっと待ってください...それは、std::stringを返すのとほとんど同じですよね。

std::string returnCharPtr()
{
    std::string someString;

    // some processing!.

    return new_string;
}

これにより、文字列が関数のスコープ外の新しい文字列にコピーされます。動作しますが、文字列の新しいコピーを作成します。

戻り値の最適化のおかげで、これはコピーを作成しません(すべての修正に感謝します!)。

したがって、別のオプションは、引数としてパラメーターを渡すことです。そのため、関数で文字列を処理しますが、新しいコピーは作成しません。 :

void returnCharPtr(std::string & someString)
{
    // some processing!.
}

または、C-Stringが必要な場合は、文字列の長さに注意する必要があります。

void returnCharPtr(char*& someString, int n) // a reference to pointer, params by ref
{
    // some processing!.
}
3
ArthurChamz

問題は、someStringが関数の最後で破棄され、関数が存在しないデータへのポインターを返すことです。

返された文字ポインタを使用する前に破棄される可能性のある文字列の.c_str()を返さないでください。

の代わりに...

const char* function()
{
    std::string someString;
    // some processing!
    return someString.c_str();
}

//...

useCharPtr(function());

使用する

std::string function()
{
    std::string someString;
    // some processing!
    return someString;
}

//...

useCharPtr(function().c_str());
1
milleniumbug

他の回答で呼び出されていない解決策。

メソッドがクラスのメンバーである場合は、次のようになります。

class A {
public:
    const char *method();
};

また、クラスインスタンスがポインタの有用性を超えて存続する場合は、次のことを実行できます。

class A {
public: 
    const char *method() {
        string ret = "abc";
        cache.Push_back(std::move(ret));
        return cache.last().c_str();
    }
private:
    vector<string> cache; //std::deque would be more appropriate but is less known
}

このようにして、ポインタはAが破棄されるまで有効です。

関数がクラスの一部ではない場合でも、クラスを使用してデータを格納できます(関数のstatic変数やグローバルに参照できる外部クラスインスタンス、またはstaticクラスのメンバー)。データを永久に保持しないために、しばらくするとデータを削除するメカニズムを実行できます。

1
coyotte508

最善の方法は、自動メモリ管理を行うstd::stringを返すことです。一方、returnCharPtr内から割り当てられたメモリを指すconst char*を実際に返す場合は、他のユーザーが明示的に解放する必要があります。

std::stringをご利用ください。

1
user2033018

あなたは文字列へのポインタを渡し、メソッドにそれを直接操作させることができます(つまり、完全にリターンを回避します)

void returnCharPtr(char* someString)
{    
    // some processing!
    if(someString[0] == 'A')
       someString++;
}
1
MrDuk

オプションは次のとおりです。

_std::string_を返す

新しい文字バッファを保持するバッファをreturnCharPtr()に渡します。これには、提供されたバッファが文字列を保持するのに十分な大きさであることを確認する必要があります。

returnCharPtr()内に新しいchar配列を作成し、バッファを新しい配列にコピーして、そのポインタを返します。これには、呼び出し側がnewで明示的に作成していないものに対して明示的に_delete []_を呼び出すか、すぐにスマートポインタークラスに配置する必要があります。このソリューションは、スマートポインターを返した場合に改善されますが、_std::string_を直接返すほうが実際的です。

最初のものを選択してください。 _std::string_を返します。これは、はるかに単純で安全なオプションです。

1
xen-0

returnCharPtrの戻り値を自由に変更できる場合は、std::stringに変更してください。これは、文字列を返す最もクリーンな方法です。できない場合は、返された文字列にメモリを割り当て、std::stringからその文字列にコピーして、割り当てられたメモリへのポインタを返す必要があります。また、呼び出し側の関数でメモリを削除する必要があります。呼び出し元はメモリの割り当てを解除する必要があるため、戻り値をchar*に変更します。

char* returnCharPtr() 
{
    std::string someString;

    // some processing!.

    char* cp = new char[someString.length()+1];
    strcpy(cp, someString.c_str());
    return cp;
}
1
R Sahu