简体   繁体   English

为什么在这里使用静态char const *而不是字符串文字会有所不同?

[英]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_funcargs... ,并且它们的生存时间是需要的。

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_morereturn语句。 Then the lifetime of that temporary char const* object immediately ends on function return. 然后,该临时char const*对象的生存期在函数返回时立即结束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么 string 在这里不起作用而 char const* 可以? - Why does string not work here while char const* does? const char *和literal string之间有什么区别? - What is the difference between const char * and literal string? 为什么我不能使用static_cast <const char**> (str)而不是(const char **)str? - Why cant i use static_cast<const char**>(str) instead of (const char**)str? 为什么现在“{static const char a [] = {...}”和“{const char a [] = {...}”之间存在差异? - Why is there now a difference between “{static const char a[]={…}” and “{const char a[]={…}”? 为什么“auto”将字符串声明为const char *而不是std :: string? - Why does “auto” declare strings as const char* instead of std::string? 为什么std :: runtime_error :: what()返回const char *而不是std :: string const& - Why does std::runtime_error::what() return const char* instead of std::string const& 静态const char *和const char之间的区别* - Difference between static const char* and const char* 静态对const局部变量有影响吗? - Does static make a difference for a const local variable? 为什么我可以将字符串文字初始化为const char *和QString而不是QString *? - Why can I initialize string literal as const char* and QString but not QString*? 使用静态const char * const代替#define - Using static const char* const instead of #define
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM