考虑以下 C++17 代码:
#include <iostream>
int read;
int main(){
std::ios_base::sync_with_stdio(false);
std::cin >> read;
}
Run Code Online (Sandbox Code Playgroud)
它可以在使用 GCC 11.2 和 Clang 12.0.1 的Godbolt上编译并正常运行,但如果使用密钥编译,则会导致运行时错误-static。
据我了解,有一个名为 POSIX(?) 的函数read(请参阅man read(2)),因此上面的示例实际上会调用 ODR 违规,并且即使在没有-static. 如果我尝试命名变量,GCC 甚至会发出警告malloc:built-in function 'malloc' declared as non-function
上面的程序是有效的 C++17 吗?如果没有,为什么?如果是,是否是编译器错误导致其无法运行?
考虑以下代码:
\n#include <cstdlib>\nstruct Foo {\n ~Foo() {\n std::exit(0);\n }\n} foo;\nint main() {\n}\nRun Code Online (Sandbox Code Playgroud)\n它在我的 Linux(GCC、Clang)和 Windows(Visual Studio)上都成功编译并以零终止。然而,当在Windows()上用MSYS2的GCC编译时g++ (Rev2, Built by MSYS2 project) 10.3.0,它会进入无限递归并因堆栈溢出而死亡。这可以通过在之前添加一些调试输出来检查std::exit();我最初没有添加它是为了避免考虑破坏std::cout.
是否有任何 C++ 标准对这种行为有任何规定?它是否定义良好/实现定义/未定义/等等,为什么?
\n例如,最近的一些草案对\ 的行为[support.start.term]/9.1进行了以下说明:std::exit
\n\n首先,销毁与当前线程关联的具有线程存储持续时间的对象。\n接下来,销毁具有静态存储持续时间的对象,并调用通过调用 atexit 注册的函数。有关销毁和调用的顺序,请参阅 [basic.start.term]。
\n
[basic.start.term]/1我猜它指的是:
\n\n具有静态存储持续时间的构造对象([dcl.init])将被销毁,并且在 std\xe2\x80\x8b::\xe2\x80\x8batexit 中注册的函数将作为 std\xe2\x80\x8b 调用的一部分被调用: :\xe2\x80\x8bexit ([support.start.term])。\n对 std\xe2\x80\x8b::\xe2\x80\x8bexit 的调用在销毁和注册函数之前排序。
\n
我没有看到对std::exit析构函数调用有任何直接限制。
旁注:请不要评论“这段代码很糟糕”、“你不应该在全局对象中使用析构函数”(你可能不应该)并在评论中探究 XY 问题。将此视为一个好奇的学生提出的学术问题,他知道对原始问题有更好的解决方案,但在探索 C++ 的广阔领域时偶然发现了这个怪癖。
\n我知道显式调用析构函数会因为双析构函数调用而导致未定义的行为,如下所示:
#include <vector>
int main() {
std::vector<int> foo(10);
foo.~vector<int>();
return 0; // Oops, destructor will be called again on return, double-free.
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我们将新位置称为"复活"对象,该怎么办?
#include <vector>
int main() {
std::vector<int> foo(10);
foo.~vector<int>();
new (&foo) std::vector<int>(5);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
更正式的:
new)然后,在该对象被破坏之前,在其上调用placement new以"恢复"它?示例用例(虽然这个问题更多是关于好奇心):我想"重新分配"一个没有的对象operator=.
我已经看到这个问题,说"覆盖"具有非静态const成员的对象是非法的.所以,让我们将这个问题的范围限制在没有任何const成员的对象上.
想象一下,我有服务器和客户端通过WebSocket进行通话.每个时间都发送另一个数据块.不同的块可以具有不同的长度.
我保证,如果服务器在一次调用中发送chunk,那么客户端将在一次message回调中收到它,反之亦然?也就是说,WebSocket是否具有嵌入式"打包"功能,所以我不必关心我的数据在传输过程中是否在几个回调中被分割,或者它不是?
考虑以下代码:
#include <iostream>
int main() {
long long x = 123456789123456789;
std::cout << std::fixed;
auto y = static_cast<double>(x); // (1)
std::cout << static_cast<long long>(y) << "\n"; // (2)
std::cout << y << "\n";
std::cout << (x == static_cast<long long>(y)) << "\n"; // (3)
std::cout << static_cast<long long>(static_cast<double>(x)) << "\n"; // (4)
std::cout << (x == static_cast<long long>(static_cast<double>(x))) << "\n"; // (5)
}
Run Code Online (Sandbox Code Playgroud)
当在 Linux 上用 32 位 GCC 编译时 ( g++ -m32 a.cpp),打印如下:
123456789123456784
123456789123456784.000000
0
123456789123456789 …Run Code Online (Sandbox Code Playgroud) 在我的C++ 11程序中,我使用shared_ptr<T>了一些主动创建和删除的对象.事实上,标准分配器operator new是一个瓶颈,所以我想创建自己的一个,它将立即分配一堆内存,然后make_shared按需提供.不幸的是,这是我第一次编写分配器,我不知道为什么GCC无法编译以下代码:
#include <memory>
class MyAlloc {
public:
typedef char* pointer;
typedef const char* const_pointer;
typedef char value_type;
char* allocate(size_t len) {
return new char[len];
}
void deallocate(char *ptr) {
delete[] ptr;
}
} my_alloc;
int main() {
std::allocator_traits<MyAlloc>();
// MyAlloc is a correct allocator, since allocator_traits can be instantiated
// If I comment the following line of code, compilation is successful
std::allocate_shared<int>(my_alloc, 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在这里,我有一个非常简单的存根分配器和一个调用allocate_shared.GCC产生的错误是:
In file included …Run Code Online (Sandbox Code Playgroud) 我只是想等待用户输入密码,然后在继续使用其余代码之前使用它.错误是Cannot read property 'then' of undefined.
let rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Password: ', password => {
rl.close();
return decrypt(password);
}).then(data =>{
console.log(data);
});
function decrypt( password ) {
return new Promise((resolve) => {
//do stuff
resolve(data);
});
}
Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
a = function() {
return (23)
}
b = function() {
return (23) * 23
}
c = function() {
return (23) * someUndefinedVariable
}
Run Code Online (Sandbox Code Playgroud)
以上所有运行成功(如果调用)并返回23.我假设R忽略了在右括号之后的所有内容return,但事实并非如此,因为此代码在代码加载期间失败:
d = function() {
return (23) something
}
Run Code Online (Sandbox Code Playgroud)
我的假设是在后一个例子中,某些词法分析器或解析器失败了.但在前者中,表达式被解析为(return(23))*some(因为return被视为函数),但是评估停止在return,因此R不会尝试查找some.
听起来不错吗?这是什么原因?这样的行为是否有意?我可以启用一些警告,以便口译员告诉我这种"无法访问的代码"吗?
考虑以下代码,它编译并运行:
#include <iostream>
#include <sstream>
struct Foo {};
void operator>>(std::istream &, Foo) {
}
int main() {
std::stringstream{} >> Foo{};
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我更改std::istream为std::stringstream,则会出现错误:
c.cpp: In function 'int main()':
c.cpp:7:25: error: no match for 'operator>>' (operand types are 'std::stringstream' {aka 'std::__cxx11::basic_stringstream<char>'} and 'Foo')
7 | std::stringstream{} >> Foo{};
| ~~~~~~~~~~~~~~ ^~ ~~~~~
| | |
| | Foo
| std::stringstream {aka std::__cxx11::basic_stringstream<char>}
c.cpp:4:6: note: candidate: 'void operator>>(std::stringstream&, Foo)' (near match)
4 | void operator>>(std::stringstream &, Foo) {
| …Run Code Online (Sandbox Code Playgroud) 受到我最近问题中讨论的启发。
存在LWG 1203 C++ 标准库问题。它变成operator>>(istream&&, T&&)了更通用的operator>>(Stream&&, T&&)(对Stream)有一些限制,因此可以保留流的类型并且可以像代码一样(stringstream{} << 123).str()工作。
据我了解,此问题已在 Varna 之前的邮件中从 WP 状态更改为 C++20 状态,此后一直没有更改。
然而, cppreference 上的这一更改提到它已追溯应用于 C++11。此外,看起来所有libstdc++、libc++和Microsoft STL也在 C++20 之前严格实现了 LWG 1203,并删除了旧的行为。
我是否遗漏了其他一些将 LWG 1203 应用于 C++11、C++14 和 C++17 的 C++ 标准备忘录?