定数のcharポインタを返すメソッドがあります。 _std::string
_を使用し、最後にc_str()
charポインタを返します。
_const char * returnCharPtr()
{
std::string someString;
// some processing!.
return someString.c_str();
}
_
COVERITYツールから、上記は適切な使用法ではないとの報告を受けました。私はグーグルで調べたところ、someString
がその破壊に遭遇するとすぐに、charポインタが返されて無効になることがわかりました。
これを踏まえて、この問題をどのように修正しますか? charポインターを正確に返す方法は?
_std::string
_を返すと、この問題は解決します。しかし、これを行う他の方法があるかどうかを知りたいです。
このコードで何が起こるか:
const char * returnCharPtr()
{
std::string someString("something");
return someString.c_str();
}
std::string
のインスタンスが作成されます-これは自動保存期間を持つオブジェクトですsomeString
が破棄され、その内部メモリがクリーンアップされます最良の解決策:オブジェクトを返す:
std::string returnString()
{
std::string someString("something");
return someString;
}
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());
}
_
この質問には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()
を忘れないでください。
まあ、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!.
}
問題は、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());
他の回答で呼び出されていない解決策。
メソッドがクラスのメンバーである場合は、次のようになります。
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
クラスのメンバー)。データを永久に保持しないために、しばらくするとデータを削除するメカニズムを実行できます。
最善の方法は、自動メモリ管理を行うstd::string
を返すことです。一方、returnCharPtr
内から割り当てられたメモリを指すconst char*
を実際に返す場合は、他のユーザーが明示的に解放する必要があります。
std::string
をご利用ください。
あなたは文字列へのポインタを渡し、メソッドにそれを直接操作させることができます(つまり、完全にリターンを回避します)
void returnCharPtr(char* someString)
{
// some processing!
if(someString[0] == 'A')
someString++;
}
オプションは次のとおりです。
_std::string
_を返す
新しい文字バッファを保持するバッファをreturnCharPtr()
に渡します。これには、提供されたバッファが文字列を保持するのに十分な大きさであることを確認する必要があります。
returnCharPtr()
内に新しいchar
配列を作成し、バッファを新しい配列にコピーして、そのポインタを返します。これには、呼び出し側がnew
で明示的に作成していないものに対して明示的に_delete []
_を呼び出すか、すぐにスマートポインタークラスに配置する必要があります。このソリューションは、スマートポインターを返した場合に改善されますが、_std::string
_を直接返すほうが実際的です。
最初のものを選択してください。 _std::string
_を返します。これは、はるかに単純で安全なオプションです。
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;
}