2017-01-18 8 views
4

このコードは未定義た行動:std :: string_view :: dataにヌルターミネータが含まれていないのはなぜですか?

#include <experimental/string_view> 
#include <iostream> 

using namespace std::experimental::string_view_literals; 

void foo(std::experimental::string_view msg) { 
    std::cout << msg.data() << '\n'; // undefined behavior if 'msg' is not null- 
            // terminated 

    // std::cout << msg << '\n'; is not undefined because operator<< uses 
    //       iterators to print 'msg', but that's not the point 
} 

int main() { 
    foo("hello"sv); // not null-terminated - undefined behavior 
    foo("foo");  // same, even more dangerous 
} 

std::string_viewは、文字列を終了null以外を格納できるということである、とdataを呼び出すときに、ヌルターミネータが含まれていない理由。すなわち、上記のコード定義された動作を行うこととして、本当に限界だ、私はそれのうちstd::stringを構築する必要があります。

std::string str{ msg }; 
std::cout << str.data() << '\n'; 

これは本当に、この場合にstd::string_viewが不要になり、私はまだfooに渡された文字列をコピーする必要があり、移動セマンティクスを使用してmsgstd::stringに変更するのはなぜですか?これはもっと速いかもしれませんが、私は測定しませんでした。私はconst char*を受け入れる関数にconst char*を渡すたびに少し不要ですが、委員会はそれをこのように決めた理由がなければならないstd::stringを構築する必要が

いずれかの方法、。

なぜ、std::string_view::dataは、std::string::dataのようなヌル終了文字列を返さないのですか?

+7

のErrが、*文字列リテラル*がnullで終了します。 – WhiZTiM

+0

@WhiZTiMどういう意味ですか? – Rakete1111

+3

私は、あなたがなぜnullを終了するために 'data'を必要とするのか見当たりません。ヌルで終了した 'const char *'を与えても、ビューはそれを保持します。あなたは1つを持っていない場合、ビューは1つを追加しません。それはIMHOの期待行動です。 – NathanOliver

答えて

13

それでは、なぜはstd :: string_view ::データは、STDのようなnull終端 文字列を返しません::文字列::データ

は、単にそれができないためです。 sring_viewは、より大きな文字列(文字列の部分文字列)をより狭く表示することができます。つまり、文字列は、特定のビューの最後にNULL終了を持つ必要はありません。明白な理由からヌルターミネータを基になる文字列に書き込むことはできません。文字列のコピーを作成してメモリリークなしでchar *を返すことはできません。

null終端文字列を使用する場合は、std::stringのコピーを作成する必要があります。

は私がstd::string_viewの良い使用をお見せしましょう:

auto tokenize(std::string_view str, Pred is_delim) -> std::vector<std::string_view> 

ここで得られたベクターは、大きな文字列にビューとしてのトークンが含まれています。

+4

ああ、私はあなたが何を意味するかを見ます。 'std :: string_view'は実際にバッファを持っていません。 – Rakete1111

+0

@ Rakete1111正確に – bolov

6

string_viewの目的は、連続した文字列を表す範囲にすることです。そのような範囲をNUL終止符で終わるものに限定することは、クラスの有用性を制限する。

実際にNUL終端された文字列からのみ作成されることを意図したstring_viewの代替バージョンを使用することは、依然として有用であると言われています。

マイzstring_viewクラスは個人string_viewから継承し、それは正面からの要素と文字列が非NULで終了することはできません他の操作を除去するためのサポートを提供しています。それは残りの操作を提供しますが、zstring_viewではなくstring_viewを返します。

あなたはこの仕事をするためにstring_viewから失うことを持っているか、いくつかの操作を驚かれることでしょう:

template<typename charT, typename traits = std::char_traits<charT>> 
class basic_zstring_view : private basic_string_view<charT, traits> 
{ 
public: 
    using base_view_type = basic_string_view<charT, traits>; 

    using base_view_type::traits_type; 
    using base_view_type::value_type; 
    using base_view_type::pointer; 
    using base_view_type::const_pointer; 
    using base_view_type::reference; 
    using base_view_type::const_reference; 

    using base_view_type::const_iterator; 
    using base_view_type::iterator; 
    using base_view_type::const_reverse_iterator; 
    using base_view_type::reverse_iterator; 

    using typename base_view_type::size_type; 
    using base_view_type::difference_type; 

    using base_view_type::npos; 

    basic_zstring_view(const charT* str) : base_view_type(str) {} 
    constexpr explicit basic_zstring_view(const charT* str, size_type len) : base_view_type(str, len) {} 
    constexpr explicit basic_zstring_view(const base_view_type &view) : base_view_type(view) {} 

    constexpr basic_zstring_view(const basic_zstring_view&) noexcept = default; 
    basic_zstring_view& operator=(const basic_zstring_view&) noexcept = default; 

    using base_view_type::begin; 
    using base_view_type::end; 
    using base_view_type::cbegin; 
    using base_view_type::cend; 
    using base_view_type::rbegin; 
    using base_view_type::rend; 
    using base_view_type::crbegin; 
    using base_view_type::crend; 

    using base_view_type::size; 
    using base_view_type::length; 
    using base_view_type::max_size; 
    using base_view_type::empty; 

    using base_view_type::operator[]; 
    using base_view_type::at; 
    using base_view_type::front; 
    using base_view_type::back; 
    using base_view_type::data; 

    using base_view_type::remove_prefix; 

    //`using base_view_type::remove_suffix`; Intentionally not provided. 

    ///Creates a `basic_string_view` that lacks the last few characters. 
    constexpr basic_string_view<charT, traits> view_suffix(size_type n) const 
    { 
     return basic_string_view<charT, traits>(data(), size() - n); 
    } 

    using base_view_type::swap; 

    template<class Allocator = std::allocator<charT> > 
    std::basic_string<charT, traits, Allocator> to_string(const Allocator& a = Allocator()) const 
    { 
     return std::basic_string<charT, traits, Allocator>(begin(), end(), a); 
    } 

    constexpr operator base_view_type() const {return base_view_type(data(), size());} 

    using base_view_type::to_string; 

    using base_view_type::copy; 

    using base_view_type::substr; 

    using base_view_type::operator==; 
    using base_view_type::operator!=; 
    using base_view_type::compare; 
}; 
+0

ああ、それは面白いです。 – Rakete1111

+0

ありがとうございますので、 'zstring_view'は文字列の末尾にのみ表示できます。面白い。 – bolov

関連する問題