即将推出的 C++20 的这种使用是否std::span正确并且没有开销来包装命令行参数?
#include <iostream>
#include <span>
int main(int argc, const char* argv[])
{
for (auto s : std::span { argv, static_cast<std::size_t>(argc) })
std::cout << s << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如果它是正确的,我可以进一步使用 withstd::string_view吗?
有几种方法可以将文本信息传递给 C++ 中的函数:可以是 c-string/std::string、按值/按引用、左值/右值、常量/可变的。C++17 在标准库中添加了一个新类:std::string_view. string_view 的语义是提供没有所有权的只读文本信息。因此,如果您只需要读取一个字符串,您可以使用:
void read(const char*); // if you need that in a c-style function or you don't care of the size
void read(const std::string&); // if you read the string without modification in C++98 - C++14
void read(std::string_view); // if you read the string without modification in C++17
Run Code Online (Sandbox Code Playgroud)
我的问题是在 C++17 中void read(const std::string&)是否应该优先考虑任何情况void read(std::string_view)。假设不需要向后兼容性。
最小可重复示例:
using namespace std;
#include<string>
#include<string_view>
#include<iostream>
int main()
{
string s = "someString";
string_view sV = string_view(s);
string_view sVTwo = string_view(begin(s), end(s));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
创建 string_view sV 的时间复杂度是否与字符串 s 中的字符数成线性关系,或者与字符串 s 的长度无关?同样,构造 sVTwo 的时间复杂度是线性的还是恒定的,取决于字符串中有多少个字符?
我感到困惑的原因是我无法分辨这里的哪些构造函数: https: //en.cppreference.com/w/cpp/string/basic_string_view/basic_string_view用于构造字符串。
为什么 GCC 和 Clang 无法编译下面的代码片段(链接)?我想返回 s 的向量std::string_view,但显然无法string_view从 中提取 s stringstream。
#include <iostream>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include <iterator>
#include <algorithm>
#include <ranges>
[[ nodiscard ]] std::vector< std::string_view >
tokenize( const std::string_view inputStr, const size_t expectedTokenCount )
{
std::vector< std::string_view > foundTokens { };
if ( inputStr.empty( ) ) [[ unlikely ]]
{
return foundTokens;
}
std::stringstream ss;
ss << inputStr;
foundTokens.reserve( expectedTokenCount );
std::copy( std::istream_iterator< std::string_view >{ ss }, …Run Code Online (Sandbox Code Playgroud) 给出以下代码,我们可以看到,std::string_view当字符串增长超出容量时,它就会失效(这里 SSO 最初生效,然后将内容放入堆上)
#include <iostream>
#include <cassert>
#include <string>
using std::cout;
using std::endl;
int main() {
std::string s = "hi";
std::string_view v = s;
cout << v << endl;
s = "this is a long long long string now";
cout << v << endl;
}
Run Code Online (Sandbox Code Playgroud)
输出:
hi
#
Run Code Online (Sandbox Code Playgroud)
因此,如果我将 string_view 存储到字符串中,然后更改字符串的内容,我可能会遇到大麻烦。鉴于现有的实现,是否有可能std::string变得更智能string_view?哪个不会面临这样的缺点?我们可以存储一个指向字符串对象本身的指针,然后确定该字符串是否更多地处于 SSO 中并相应地工作。(虽然不确定这如何处理文字字符串,所以也许这就是为什么不这样做的原因? )
我知道这string_view类似于存储返回值,string::c_str()但考虑到我们有这个包装器,std::string我认为很多使用此功能的人不会遇到这个问题。大多数免责声明是为了确保所指向的内容std::string在范围内,但这完全是一个不同的问题。
#include <iostream>
std::string_view return_string_view();
using namespace std;
int main()
{
string got;
auto peeked = return_string_view();
got += peeked;
cout << got << endl;
return 0;
}
string_view return_string_view()
{
string const s = string().assign( 2, 'x' );
auto sv = string_view( s.c_str() );
return sv;
}
Run Code Online (Sandbox Code Playgroud)
操作系统版本
Linux vm 5.19.0-45-generic #46-Ubuntu SMP PREEMPT_DYNAMIC Wed Jun 7 09:08:58 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)
海湾合作委员会版本
Linux vm 5.19.0-45-generic #46-Ubuntu SMP PREEMPT_DYNAMIC Wed Jun 7 09:08:58 UTC 2023 x86_64 x86_64 x86_64 …Run Code Online (Sandbox Code Playgroud) 我正在使用不同编译器的std :: string_view,并注意到每个编译器在使用非null终止的char数组初始化std :: string_view时会打印出不同的大小.
似乎每个编译器在打开优化时打印出正确的大小,但在优化关闭时打印出错误的大小(GCC除外,它在两种情况下都打印出正确的大小).
我的问题是:为什么会这样?
码:
// test.cpp
#include <iostream>
#ifdef __MINGW32__
#include <experimental/string_view>
#elif _MSC_VER
#include <string_view>
#endif
int main()
{
const char foo[3]{ 'f','o','o' };
#ifdef __MINGW32__
std::experimental::string_view str_v{ foo };
#elif _MSC_VER
std::string_view str_v{ foo };
#endif
std::cout << sizeof(foo) << " " << str_v.size() << '\n';
}
Run Code Online (Sandbox Code Playgroud)
输出:Visual C++ 19.00.24619.0
3 5 // cl /Zi /std:c++latest /EHsc /nologo /W4 test.cpp
3 3 // cl /O2 /std:c++latest /EHsc /nologo /W4 test.cpp …Run Code Online (Sandbox Code Playgroud) std::string_view使用临时初始化a是一个常见的错误std::string。
using namespace std::literals;
std::string_view sv1 = "foo" ; // good
std::string_view sv2 = "bar"s; // bad: "foo"s will expire
std::cout << sv1 << "\n" // outputs foo
<< sv2 << "\n"; // undefined behavior
Run Code Online (Sandbox Code Playgroud)
这是因为"bar"s,临时表达式std::string在完整表达式的末尾被销毁了。
但是"foo"sv呢?
std::string_view sv3 = "baz"sv;
Run Code Online (Sandbox Code Playgroud)
当然这应该起作用,因为后缀sv否则是没有用的。但是,这与之"baz"s有何根本区别?换句话说,为什么引入的字符串"baz"sv不过期?
我想将宏定义为字符串,稍后在编译时包含基于字符串比较的代码:
#include <iostream>
#include <string_view>
constexpr bool strings_equal(char const * a, char const * b) {
return std::string_view(a)==b;
}
#define FOO "bar"
int main() {
#if strings_equal( FOO, "bar") == 0
std::cout << "got a bar!" << '\n';
#endif
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译这个
$ g++ -std=c++17 test.cpp -o my_test
Run Code Online (Sandbox Code Playgroud)
给出错误:
test.cpp:12:18: error: missing binary operator before token "("
12 | #if strings_equal( FOO, "bar") == 0
| ^
Run Code Online (Sandbox Code Playgroud)
编辑:
看来#if指令是否在函数内部很重要,因为如果它在函数内部,我们可以用它替换它if constexpr (...) { ... }但是如果它在 …
这是输入(有点)std::string_view变量的正常方法:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str; // Still have to use std::string class // Resulting in stack/heap allocation
getline(cin, str);
string_view view(str);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我想知道有什么方法可以直接输入std::string_view而不必使用字符串类(使用堆分配)???
[我肯定知道字符串文字(如“Hello”)在编译时直接存储在二进制代码中,而不会导致任何堆栈/堆分配......所以也许可以通过任何方式将字符串文字直接输入到 string_view 中???]
注意:我希望用户输入不是代码中的硬编码字符串!
根据https://en.cppreference.com/w/cpp/string/basic_string_view/basic_string_view,std::basic_string_view类有 7 个重载的 ctor。我只关心其中的两个,因为现在我不在我的代码中使用其余的。
这些是我关心的实例:
constexpr basic_string_view( const CharT* s, size_type count );
constexpr basic_string_view( const CharT* s );
Run Code Online (Sandbox Code Playgroud)
我需要防止代码调用第二个代码(因为它可能导致非空终止缓冲区的缓冲区溢出)。
我有类似下面的内容:
#include <iostream>
#include <sstream>
#include <string>
#include <array>
void func( const std::string_view str )
{
if ( str.empty( ) )
{
return;
}
std::stringstream ss;
if ( str.back( ) == '\0' )
{
ss << str.data( );
}
else
{
ss << std::string{ str };
}
}
int main()
{
std::array<char, 20> buffer { }; …Run Code Online (Sandbox Code Playgroud) 假设我们有一个 string_view 和另一个 string_view,它是第一个 string_view 的子集:
using namespace std; // just to shorten the example...
string_view s{"abc def"};
auto t = s.substr(4);
auto u = s.substr(0, 4);
cout << *(s.begin() + 4) << " " << *t.begin() << '\n';
cout << ((s.begin() + 4) == t.begin());
cout << (s.end() == t.end());
cout << ((s.begin() +5) == t.begin());
cout << ((s.begin() +5) == (t.begin() + 1));
cout << ((s.begin() + 4) == u.end()); // true
Run Code Online (Sandbox Code Playgroud)
所有比较都可以在 gcc (9 HEAD) 和 clang …
一个std::string_view参数比const char*下面代码中的一个参数更好吗?
void func( const std::string_view str )
{
std::istringstream iss( str.data( ) ); // str is passed to the ctor of istringstream
std::size_t pos { };
int num { std::stoi( str.data( ), &pos, 10 ) }; // and here it's passed to std::stoi
}
int main()
{
std::array<char, 20> buffer { };
std::cin.getline( buffer.data( ), 20 );
func( buffer.data( ) );
}
Run Code Online (Sandbox Code Playgroud)
std::istringstreamctor 和都std::stoi需要 aconst std::string&作为参数。但我std::string_view使用其data()成员函数向他们传递一个对象。这是不好的做法吗?我应该回到 …