为什么字符串文本不作为对数组的引用而不是不透明指针传递?
Why aren't string literals passed as references to arrays instead of opaque pointers?
在C++中,字符串文字的类型为const char [N]
,其中N
与std::size_t
一样,是字符数加1(零字节终止符)。它们驻留在静态存储器中,从程序初始化到终止都可用。
通常,采用常量字符串的函数不需要std::basic_string
接口,或者更喜欢避免动态分配;例如,他们可能只需要字符串本身及其长度。尤其是std::basic_string
,必须提供一种从该语言的原生字符串文本构建的方法。这样的函数提供了一个采用C样式字符串的变体:
void function_that_takes_a_constant_string ( const char * /*const*/ s );
// Array-to-pointer decay happens, and takes away the string's length
function_that_takes_a_constant_string( "Hello, World!" );
正如这个答案中所解释的,数组会衰减为指针,但它们的维度会被删除。在字符串文字的情况下,这意味着它们的长度(在编译时已知)将丢失,并且必须在运行时通过在指向内存中迭代直到找到零字节来重新计算。这不是最优的。
然而,字符串文字,以及通常的数组,可以使用模板参数推导作为引用传递,以保持其大小:
template<std::size_t N>
void function_that_takes_a_constant_string ( const char (& s)[N] );
// Transparent, and the string's length is kept
function_that_takes_a_constant_string( "Hello, World!" );
模板函数可以充当另一个函数(实际函数)的代理,该函数将使用一个指向字符串及其长度的指针,从而避免代码暴露并保持长度。
// Calling the wrapped function directly would be cumbersome.
// This wrapper is transparent and preserves the string's length.
template<std::size_t N> inline auto
function_that_takes_a_constant_string
( const char (& s)[N] )
{
// `s` decays to a pointer
// `N-1` is the length of the string
return function_that_takes_a_constant_string_private_impl( s , N-1 );
}
// Isn't everyone happy now?
function_that_takes_a_constant_string( "Hello, World!" );
为什么不更广泛地使用它?特别是,为什么std::basic_string
没有一个具有提议签名的构造函数?
注意:我不知道提议的参数是如何命名的;如果你知道怎么做,请给问题的标题建议一个版本。
从某种意义上说,这在很大程度上是历史性的。虽然你是正确的,没有真正的原因不能做到这一点(如果你不想使用整个缓冲区,请传递一个长度参数,对吧?)但如果你有一个字符数组,它通常是一个缓冲区,而不是你在任何时候都在使用的所有缓冲区:
char buf[MAX_LEN];
由于这是通常的使用方式,因此似乎没有必要甚至为const CharT (&)[N]
添加新的basic_string
构造函数模板。
不过,整件事还很难说。
添加这样一个模板化重载的问题很简单:
无论何时使用 演示代码(在coliru上): 请记住:如果你在C中谈论一个字符串,它总是表示一个以0结尾的字符串,而在C++中,它也可以表示一个char
-类型的静态缓冲区调用函数,都会使用它,即使缓冲区不是作为一个字符串的整体,并且您确实希望只传递初始字符串(嵌入的零远不如终止的零常见,并且使用缓冲区的一部分非常常见#include <stdio.h>
#include <string.h>
auto f(const char* s, size_t n) {
printf("char* size_t %un", (unsigned)n);
(void)s;
}
auto f(const char* s) {
printf("char*n");
return f(s, strlen(s));
}
template<size_t N> inline auto
f( const char (& s)[N] ) {
printf("char[&u]n");
return f(s, N-1);
}
int main() {
char buffer[] = "Hello World";
f(buffer);
f(+buffer);
buffer[5] = 0;
f(buffer);
f(+buffer);
}
std::string
,它是计数的。
我相信这是在C++14中基于用户定义的字符串文字解决的
http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s
#include <string>
int main()
{
//no need to write 'using namespace std::literals::string_literals'
using namespace std::string_literals;
std::string s2 = "abc def"; // forms the string "abc"
std::string s1 = "abc def"s; // form the string "abc def"
}
您可以创建助手类来修复此问题,而无需为每个函数使用重载
struct string_view
{
const char* ptr;
size_t size;
template<size_t N>
string_view(const char (&s)[N])
{
ptr = s;
size = N;
}
string_view(const std::string& s)
{
ptr = s.data();
size = s.size() + 1; // for ' ' at end
}
};
void f(string_view);
main()
{
string_view s { "Hello world!" };
f("test");
}
您应该为助手函数(如begine
和end
)扩展这个类,以简化程序中的使用。
- 如何在不使用指针的情况下将派生类的对象作为参数传递给基类中的函数?
- 在函数中返回无符号字符数组,但不返回指针
- 如何创建子窗口是透明的,父窗口是不透明的?
- 从静态库使用时隐藏不透明结构的内容
- 对于指向C++类的不透明C指针,正确的typedef是什么
- 处理 pybind11 中的不透明指针
- 如何处理JNA中的不透明指针
- 如何在c++绑定中用不透明指针包装c库
- 指向shared_ptr的不透明类型 C 指针
- 向上投射不透明指针
- 将不透明指针包裹在shared_ptr中
- 为什么字符串文本不作为对数组的引用而不是不透明指针传递?
- 通过不透明指针获取xml数据
- 我应该为我的不透明对象使用整数ID还是指针?
- 不透明指针(pimpl)、信号和槽
- 模板和不透明指针是否在继承上不兼容
- 如何在作用域指针类中正确使用动态分配的不透明指针
- 我可以使用' bool '类型或不透明指针指向导出到c的c++函数中的类吗?
- 如果使用未命名结构体或未定义标记实现不透明指针
- 指向具有模板成员的结构体的不透明指针