参照パラメータを持つ可変引数の使用には注意が必要ですか?質問する

参照パラメータを持つ可変引数の使用には注意が必要ですか?質問する

私はこのコードを持っています(要約)...

AnsiString working(AnsiString format,...)
{
    va_list argptr;
    AnsiString buff;

    va_start(argptr, format);
    buff.vprintf(format.c_str(), argptr);

    va_end(argptr);
    return buff;
}

そして、可能な場合は参照渡しが優先されるという前提で、このように変更しました。

AnsiString broken(const AnsiString &format,...)
{
    /* ... the rest, totally identical ... */
}

私の呼び出しコードは次のようになります:

AnsiString s1 = working("Hello %s", "World"); // prints "Hello World"
AnsiString s2 = broken("Hello %s", "World");  // prints "Hello (null)"

これは動作の仕方によるものだと思いますva_startが、何が起こっているのか正確にはわかりません。

ベストアンサー1

va_start が何に展開されるかを見れば、何が起こっているかがわかります。

va_start(argptr, format); 

(大体)

argptr = (va_list) (&format+1);

format が値型の場合、すべての可変引数の直前のスタックに配置されます。format が参照型の場合、アドレスのみがスタックに配置されます。参照変数のアドレスを取得すると、引数のアドレスではなく、アドレスまたは元の変数 (この場合は、Broken を呼び出す前に作成された一時的な AnsiString) が取得されます。

完全なクラスを渡したくない場合は、ポインターで渡すか、ダミー引数を入れるかのいずれかのオプションがあります。

AnsiString working_ptr(const AnsiString *format,...)
{
    ASSERT(format != NULL);
    va_list argptr;
    AnsiString buff;

    va_start(argptr, format);
    buff.vprintf(format->c_str(), argptr);

    va_end(argptr);
    return buff;
}

...

AnsiString format = "Hello %s";
s1 = working_ptr(&format, "World");

または

AnsiString working_dummy(const AnsiString &format, int dummy, ...)
{
    va_list argptr;
    AnsiString buff;

    va_start(argptr, dummy);
    buff.vprintf(format.c_str(), argptr);

    va_end(argptr);
    return buff;
}

...

s1 = working_dummy("Hello %s", 0, "World");

おすすめ記事