[英]Why does it make a difference to use a static char const* instead of a string literal here?
In the code below (with a link here ) g++ produces an executable that prints garbage (while clang++ doesn't) unless I define THIS_WORKS
. 在下面的代码(具有链接这里 )克++产生打印不需要的(而铛++不),除非我定义可执行
THIS_WORKS
。
The difference being, 区别在于
#ifdef THIS_WORKS
static char const* empty_string = "";
return { separator, empty_string, args... };
#else
return { separator, "", args... };
#endif
It greatly surprises me that this even can make a difference. 这甚至可以有所作为,这让我感到非常惊讶。 The only reasons that I can come up with is that this has be a compiler bug, or is Undefined Behavior in the program itself that I am missing.
我能提出的唯一原因是这是一个编译器错误,或者是我所缺少的程序本身的未定义行为。
What is going on here? 这里发生了什么? Why does g++ print garbage instead of a leading
""
? 为什么g ++会打印垃圾而不是前面的
""
?
Here is the complete compilable code snippet: 这是完整的可编译代码段:
#include <tuple>
#include <iostream>
template<typename ...Args>
struct Join
{
char const* m_separator;
std::tuple<Args const&...> m_args;
Join(char const* separator, Args const&... args) : m_separator(separator), m_args(args...) { }
template<size_t ...I> void print_on(std::ostream& os, std::index_sequence<I...>);
};
template<typename ...Args>
template<size_t ...I>
void Join<Args...>::print_on(std::ostream& os, std::index_sequence<I...>)
{
(..., (os << (I == 0 ? "" : m_separator) << std::get<I>(m_args)));
}
template<typename ...Args>
std::ostream& operator<<(std::ostream& os, Join<Args...> comm)
{
comm.print_on(os, std::make_index_sequence<sizeof...(Args)>());
return os;
}
template<typename ...Args>
Join<Args...> join(char const* separator, Args const&... args)
{
return { separator, args... };
}
template<typename ...Args>
Join<char const*, Args...> join_more(char const* separator, Args const&... args)
{
#ifdef THIS_WORKS
static char const* empty_string = "";
return { separator, empty_string, args... };
#else // THIS_DOES_NOT
return { separator, "", args... };
#endif
}
template<typename... Args>
void test_func(Args... args)
{
std::cout << join_more(", ", args...) << std::endl;
}
int main()
{
test_func(1, 2, 3);
}
The expected output is: 预期的输出是:
, 1, 2, 3
,1,2,3
Namely, join_more
is intended to print a template pack where each argument is prepended with a comma. 即,
join_more
用于打印模板包,其中每个参数前面都带有逗号。 join
doesn't print a leading comma for the first argument. join
不会为第一个参数显示逗号。
The version with THIS_WORKS
defined is fine, but yes, without THIS_WORKS
the program has undefined behavior. 定义
THIS_WORKS
的版本很好,但是可以,如果没有THIS_WORKS
则程序具有未定义的行为。
The code calls the specialization join_more<int, int, int>
, which returns a Join<char const*, int, int, int>
. 该代码调用特殊化
join_more<int, int, int>
,它返回Join<char const*, int, int, int>
。 That class type has a member of type std::tuple<char const* const&, int const&, int const&, int const&>
. 该类类型具有类型为
std::tuple<char const* const&, int const&, int const&, int const&>
。 The int const&
elements refer to the args...
of test_func
, and those live as long as needed. int const&
元素引用了test_func
的args...
,并且它们的生存时间是需要的。
But the first element of the tuple
is not so lucky. 但是
tuple
的第一个元素并不是那么幸运。 It's true the string literal's const char[1]
object containing '\\0'
has no effective end to its lifetime. 的确,包含
'\\0'
的字符串文字的const char[1]
对象没有有效的寿命期限。 But the actual tuple element is a char const* const&
reference. 但是实际的元组元素是
char const* const&
引用。 With THIS_WORKS
, it refers to the object empty_string
, which also lives long enough. 使用
THIS_WORKS
,它引用对象empty_string
,该对象的empty_string
也足够长。 Without THIS_WORKS
, the compiler needs to create a temporary char const*
object to initialize the second argument of constructor Join<const char*, int, int, int>::Join(char const*, char const* const&, int const&, int const&, int const&)
for the return
statement of join_more
. 如果没有
THIS_WORKS
,则编译器需要创建一个临时char const*
对象以初始化构造函数Join<const char*, int, int, int>::Join(char const*, char const* const&, int const&, int const&, int const&)
for join_more
的return
语句。 Then the lifetime of that temporary char const*
object immediately ends on function return. 然后,该临时
char const*
对象的生存期在函数返回时立即结束。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.