par*_*par 10 c++ arguments parameter-passing string-literals
我想知道在 C++ 中是否可以声明一个必须是字符串文字的函数参数?我的目标是接收一个对象,我只能保留指向它的指针,并且知道它不会free()从我下面被删除(即具有应用程序生命周期范围)。
例如,假设我有类似的东西:
#include <string.h>
struct Example {
Example(const char *s) : string(s) { }
const char *string;
};
void f() {
char *freeableFoo = strdup("foo");
Example e(freeableFoo); // e.string's lifetime is unknown
Example e1("literalFoo"); // e1.string is always valid
free(freeableFoo);
// e.string is now invalid
}
Run Code Online (Sandbox Code Playgroud)
如示例所示,当ed 时,该freeableFoo成员变得无效。这一切都是在你没有意识到的情况下发生的。free()e.stringExample
显然,如果在其构造函数中复制字符串,我们可以解决这个问题Example,但我不想为副本分配内存。
的构造函数是否可以Example声明“您必须传递字符串文字”(在编译时强制执行),以便知道Example它不必复制字符串并且知道其string指针在应用程序的生命周期内有效?
在 C++20 中,您可以使用一个包装类来完成此操作,consteval该类具有一个接受字符串文字的转换构造函数:
struct literal_wrapper
{
template<class T, std::size_t N, std::enable_if_t<std::is_same_v<T, const char>>...>
consteval literal_wrapper(T (&s)[N]) : p(s) {}
char const* p;
};
Run Code Online (Sandbox Code Playgroud)
这个想法是字符串文字具有类型const char[N]并且我们匹配它。
然后,您可以在想要强制传递字符串文字的地方使用此包装类:
void takes_literal(string_literal lit) {
// use lit.p here
}
Run Code Online (Sandbox Code Playgroud)
您可以将其称为foo("foobar").
请注意,这也将匹配静态存储const char[]数组,如下所示:
const char array[] = {'a'};
takes_literal(array); // this compiles
Run Code Online (Sandbox Code Playgroud)
然而,静态数组具有与字符串文字大部分相同的特征,例如无限的存储持续时间,这可能适合您。
它与本地数组不匹配,因为衰减的指针值不是常量表达式(这就是consteval出现的地方)。
这个答案几乎直接复制自 CM对问题的评论中建议的第一个变体。
只需让构造函数显式采用右值即可:
struct Example {
Example(const char*&& s) : string(s) { }
const char* string;
};
Run Code Online (Sandbox Code Playgroud)