🌟

MSVC + std::shared_ptr で false が通ってしまう

2024/07/16に公開9
std::shared_ptr<int> myfun() {
    return false;
}

int main() {
    std::shared_ptr<int> a = myfun();
    if(!a) {
        std::puts("bora");
    }
}

MSVC だとコンパイルが通る. clang/gcc だと

 could not convert ‘false’ from ‘bool’ to ‘std::shared_ptr<int>' ...

とエラーが出る.

return 0 とすると両方でコンパイルが通る.

MSVC は false を 0 で定義しているため?

理想は?

nullptr がよいようであるが, なんかややこしい... 0 がよかったりするんじゃろか?

https://yohhoy.hatenadiary.jp/entry/20120623/p1

Discussion

yaito3014yaito3014

手元で試したところ Visual Studio 2019 のビルドツールである MSVC v142 からは適切にエラーとなるようです
それ以前のビルドツールでは std::nullptr_tfalse から変換できてしまったためにコンパイルが通っていました

齊藤敦志齊藤敦志

これは欠陥報告が上がって修正された C++ の仕様側の変更に対しての修正が遅れたのだと思います。 古い C++ では「値がゼロの整数定数式は空ポインタリテラルとして使える」というルール (おそらく C の規則をそのまま真似した) があり、 bool は整数型の一種なのでこのルールだと false は空ポインタとして解釈しうるはずです。

現在の C++ はリテラルの 0 に限って空ポインタとして解釈するように改められています。

syoyosyoyo

ありがとうございます!

https://godbolt.org/z/85PPnsxxK

compiler explorer では MSVC v19(VS2024?)でもコンパイルできていました...

いずれにせよ false はよくなくて, 理想は nullptr でしょうか..

山田(ymd)山田(ymd)

nullptr がよいようであるが, なんかややこしい... 0 がよかったりするんじゃろか?

いずれにせよ false はよくなくて, 理想は nullptr でしょうか..

どうコードを書くべきかという観点のお話でしたら、暗黙のオブジェクト構築に依存せずに、
デフォルトコンストラクターで空のスマートポインタを返すのが明確で良いのではないかと思います。

Move Semantics なり、Return Value Optimization なりで、
問題になるようなレベルの性能劣化は怒らないと思います。

#include <memory>
#include <cstdio>

std::shared_ptr<int> myfun() {
    return std::shared_ptr<int>();
}

int main() {
    std::shared_ptr<int> a = myfun();
    if(!a) {
        std::puts("bora");
    }
}

何度も長い型名をタイプしたくないということでしたら、 auto を使って逃げる手もありますね。
型の間違いチェックのために明示したい事とのトレードオフですが。

#include <memory>
#include <cstdio>

auto myfun() {
    return std::shared_ptr<int>();
}

int main() {
    const auto a = myfun();
    if(!a) {
        std::puts("bora");
    }
}
syoyosyoyo

なるほど! ありがとうございます!

どうコードを書くべきかという観点のお話でしたら、暗黙のオブジェクト構築に依存せずに、
デフォルトコンストラクターで空のスマートポインタを返すのが明確で良いのではないかと思います。

白山風露白山風露

compiler explorer では MSVC v19(VS2024?)でもコンパイルできていました...

MSVCでのC++17指定のコンパイラオプションは -std=c++17 ではなく -std:c++17 ですね

syoyosyoyo

MSVC だと /std:c++17 ですね. 結果は同じ(コンパイルは通る)でした

白山風露白山風露

-/ は互換性のためどちらでも同じですが、確かに c++17 でも通りますね。 c++20 だとエラーになりました。