3

関数に渡された「文字列」(どのような表現でも) がその関数によって有効な文字列であると想定できる方法が C++ にあるかどうか疑問に思っていました。

私はC / C ++に非常に慣れていませんが、私が見る限り、Cではその質問はデフォルトで回答されています。これは、他に方法がなく、確認する必要があることを知っているだけだからです。

#include <stdio.h>

void foo(const char *str)
{
    if (str)
        printf("%s\n", str);
}

int main()
{
    char *name = "Jack";
    foo(name);

    return 0;
}

しかし、C++ は参照のような追加のものを提供するので、チェックする必要がないような方法で foo() を書くことができるかどうか疑問に思っていました。私はこのように試しました:

#include <iostream>
#include <string>

void foo(const std::string &str)
{
    std::cout << str << std::endl;
}

int main(void)
{
    std::string name = "Jack";
    foo(name);

    std::string *str = NULL;
    foo(*str);

    return 0;
}

しかし、ご覧のとおり、foo() をだまして SegFault に陥らせることができます。だから、何があっても常にチェックする必要があると思いますか?

編集#1:

わかりました、まず最初に、すべての回答と今後の回答に感謝します。

これまでに学んだことをまとめると、次のようになります。

C++ には、実際の関数呼び出しによる誤用を排除するために関数定義を記述する構文上の方法はありません。

あれは正しいですか?もしそうなら、私は元の質問に答えたように見えます。

そこで、foo() をできる限り防御的に記述して、foo() を犬のように扱っても、SegFault が発生しないようにします。

CI では、次のように記述します (短絡評価を想定):

#include <stdio.h>

void foo(const char *str, const size_t len)
{
    if (str && (str[len - 1] == '\0'))
        printf("%s\n", str);
}

int main()
{
    char *name = "Jack";
    foo(name, 5);

    /* possible mistakes, but foo can handle them */
    foo(name, 4);
    foo(name, -1);
    foo(NULL, 5);

    return 0;
}

そしてC ++で私はこれを試しています:

#include <iostream>
#include <string>

void foo(const std::string &str)
{
    if (&str)
        std::cout << str << std::endl;
}

int main(void)
{
    std::string name = "Jack";
    foo(name);

    std::string *str = NULL;
    foo(*str);

    return 0;
}

...しかし、それが適切かどうか、またはこの場合の例外を除いて何をするか、できるか、またはすべきかはわかりません。

どう思いますか?構文で誤用を防ぐことができない場合は、予防措置を強化する必要がありますか?

4

2 に答える 2

9
std::string *str = NULL;
foo(*str);

これは、呼び出し側の未定義の動作です。あなたの問題ではありません。いいえ、あなた(の作者foo)はチェックする必要はありません。

C でも、ポインターを使用すると、必ずしもチェックする必要はありません。文書化するだけです。「引数は、有効な null で終わる文字列を指している必要があります。そうでない場合、呼び出しは未定義の動作です。」-- ユーザーが NULL を渡す場合、つまり、ユーザーの問題です。これは常に行われます。そうでない場合は、次のようにすべてのレベルでポインターの有効性をチェックする無駄な呼び出しチェーンが発生します。

void foo(const char * s)
{
    if (s)
        printf("%s", s);
}

void bar(const char * s)
{
    if (s)
        foo(s);
}

void baz(const char * s)
{
    if (s)
        bar(s);
}
于 2013-06-09T12:02:11.843 に答える
2

いいえ、あなたは正しくありません。

2 番目のコードでは、関数に到達する前にポインターを逆参照すると、未定義の動作が発生します。

これはあなたの機能の問題ではありません。関数内では、2 番目の署名を使用すると、有効な文字列があると常に仮定できるため、最初の署名よりも優れています。

于 2013-06-09T12:03:43.817 に答える