C++ C++;有新的标准版本吗?
(我在寻找一两个例子来证明这一点,而不是一个列表。) <是否曾经有过这样的情况:C++标准(例如从98到11, 11到14)的改变改变了现有的、格式良好的、定义的行为用户代码的行为——默默地?i、 e.使用较新的标准版本编译时是否没有警告或错误 注:C++ C++;有新的标准版本吗?,c++,language-lawyer,standardization,C++,Language Lawyer,Standardization,(我在寻找一两个例子来证明这一点,而不是一个列表。) =201103L 涉及记忆模型的答案很好 代码>字符串::数据在C++ 17中从 const char */> >改为 char */COD>。这肯定会有所不同 void func(char* data) { cout << data << " is not const\n"; } void func(const char* data) { cout << data &
- 我问的是标准强制的行为,而不是实现者/编译器作者的选择
- 代码越不做作越好(作为对这个问题的回答)
- 我指的不是带有版本检测的代码,比如
#if u cplusplus>=201103L
- 涉及记忆模型的答案很好
<>代码>字符串::数据<代码>在C++ 17中从<代码> const char */> >改为<代码> char */COD>。这肯定会有所不同
void func(char* data)
{
cout << data << " is not const\n";
}
void func(const char* data)
{
cout << data << " is const\n";
}
int main()
{
string s = "xyz";
func(s.data());
}
void func(字符*数据)
{
cout的答案显示了使用单个size\u类型
值初始化向量如何导致C++03和C++11之间的不同行为
std::vector<Something> s(10);
C++03将默认使用v==0构建一个Something
,然后从该对象再复制十个。最后,向量包含十个对象,其v
值为1到10,包括1到10
C++11将默认构造每个元素。不制作任何副本。最后,向量包含10个对象,其v
值为0到9,包括0到9。标准中有一个中断更改列表。这些更改中的许多更改可能导致无提示的行为更改
例如:
int f(const char*); // #1
int f(bool); // #2
int x = f(u8"foo"); // until C++20: calls #1; since C++20: calls #2
哦,男孩……很可怕
其他C++ 20不允许C++结构的C样式结构声明。
typedef struct
{
void member_foo(); // Ill-formed since C++20
} m_struct;
如果你被教导编写这样的结构(教授“C带类”的人就是这样教的),你就完蛋了。每次他们向标准库添加新方法(通常是函数)时,都会发生这种情况
假设您有一个标准库类型:
struct example {
void do_stuff() const;
};
非常简单。在一些标准修订版中,添加了一个新方法或重载或任何内容旁边的内容:
struct example {
void do_stuff() const;
void method(); // a new method
};
<>这可以悄悄地改变现有C++程序的行为。
这是因为C++目前有限的反射功能足以检测是否存在这样的方法,并基于它运行不同的代码
template<class T, class=void>
struct detect_new_method : std::false_type {};
template<class T>
struct detect_new_method< T, std::void_t< decltype( &T::method ) > > : std::true_type {};
从类中删除方法时也会发生同样的情况
虽然此示例直接检测某个方法的存在,但间接发生的此类事情可能不太人为。作为一个具体示例,您可能有一个序列化引擎,该引擎根据某个对象是否可序列化,或者该对象是否具有指向原始字节的数据和大小m来决定是否可以将其序列化为容器余烬,其中一个优先于另一个
该标准将.data()
方法添加到容器中,然后类型突然改变了用于序列化的路径
所有C++标准都能做到的,如果它不想冻结,是让那种默默地中断的代码是罕见的或某种不合理的。
< p>我不确定你是否认为这是一个突破性的改变来更正代码,但是…<…>
在C++11之前,编译器被允许(但不是必须)在某些情况下省略副本,即使副本构造函数有明显的副作用。现在我们保证了副本省略。行为基本上从定义的实现转变为需要的实现
这意味着您的复制构造函数的副作用可能在较旧的版本中出现,但在较新的版本中永远不会出现。您可能会认为正确的代码不应该依赖于实现定义的结果,但我认为这与说这样的代码不正确并不完全相同。Trigraphs
源文件在物理字符集中编码,该物理字符集以实现定义的方式映射到标准中定义的源字符集。为了适应某些物理字符集的映射,这些物理字符集本机不具备源字符集所需的所有标点符号,语言定义的三角图顺序为三个常用字符的集合,可以用来代替不太常用的标点符号。需要预处理器和编译器来处理这些集合
在C++17中,trigraphs被删除。因此,一些源文件不会被新的编译器接受,除非它们首先从物理字符集转换到另一个物理字符集,该物理字符集将一对一映射到源字符集。(实际上,大多数编译器只是将trigraphs的解释设置为可选。)这不是一个微妙的行为改变,而是一个突破性的改变,它阻止了以前可以接受的源文件在没有外部翻译过程的情况下被编译
有关char
该标准还涉及执行字符集,执行字符集由实现定义,但必须至少包含整个源字符集和少量控制代码
C++标准定义为代码> char < /C>作为一个可能的无符号整数类型,它可以有效地表示执行字符集中的每一个值。用一个语言的律师的代表,你可以认为<代码> char < /代码>必须至少有8位。
如果您的实现对char
使用无符号值,那么您知道它的范围可以是0到255,因此适合存储每个可能的字节值
但是,如果您的实现使用有符号的值,那么它有选项
大多数会使用2的补码,使char
的最小范围为-128到127,即256个唯一值
但另一个选项是sign+magnity,其中保留一位表示数字是否为负数,其他七位表示大小。这将使char
的范围为-127到127,仅为255
template<class T, class=void>
struct detect_new_method : std::false_type {};
template<class T>
struct detect_new_method< T, std::void_t< decltype( &T::method ) > > : std::true_type {};
void task( std::false_type ) {
std::cout << "old code";
};
void task( std::true_type ) {
std::cout << "new code";
};
int main() {
task( detect_new_method<example>{} );
}
template<int I> struct X { static int const c = 2; };
template<> struct X<0> { typedef int c; };
template<class T> struct Y { static int const c = 3; };
static int const c = 4;
int main() { std::cout << (Y<X< 1>>::c >::c>::c) << '\n'; }
#include <iostream>
#include <sstream>
int main(int, char **)
{
int a = 12345;
std::string s = "abcd"; // not an integer, so will fail
std::stringstream ss(s);
ss >> a;
std::cout << "fail = " << ss.fail() << " a = " << a << std::endl; // since c++11: a == 0, before a still 12345
}