这特别是关于C++ 11:
#include <iostream>
struct A {
A(){}
int i;
};
struct B : public A {
int j;
};
int main() {
B b = {};
std::cout << b.i << b.j << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
用g ++ 8.2.1编译:
$ g++ -std=c++11 -pedantic-errors -Wuninitialized -O2 a.cpp
a.cpp: In function ‘int main()’:
a.cpp:25:25: warning: ‘b.B::<anonymous>.A::i’ is used uninitialized in this function [-Wuninitialized]
std::cout << b.i << " " << b.j << std::endl
Run Code Online (Sandbox Code Playgroud)
gcc检测b.i
为未初始化,但我认为它应该与零一起进行零初始化b.j
.
我相信正在发生的事情(特别是C++ 11,来自ISO/IEC工作草案N3337,强调我的):
B …
c++ initialization language-lawyer c++11 list-initialization
鉴于这个例子:
int g_i = 10;
struct S {
operator int&(){ return g_i; }
};
int main() {
S s;
int& iref1 = s; // implicit conversion
int& iref2 = {s}; // clang++ error, g++ compiles fine:
// `s` is converted
// to a temporary int and binds with
// lvalue reference
int&& iref3 = {s}; // clang++ compiles, g++ error:
// cannot bind rvalue reference
// to lvalue
}
Run Code Online (Sandbox Code Playgroud)
错误如评论中所述.
使用gcc 8.2.1和clang 7.0.1,并且不同意本例中发生的情况.有人可以澄清一下吗?
否则,如果初始化程序列表具有 …
Folly为 C++20 风格的协程提供了一个可用的库。
在自述文件中,它声称:
重要提示:您需要非常小心临时 lambda 对象的生命周期。调用 lambda 协程会返回一个 folly::coro::Task 捕获对 lambda 的引用,因此如果返回的 Task 没有立即 co_awaited 那么当临时 lambda 超出范围时,任务将留下悬空引用。
我尝试为他们提供的示例制作 MCVE,但对结果感到困惑。为以下所有示例假设以下样板:
#include <folly/experimental/coro/Task.h>
#include <folly/experimental/coro/BlockingWait.h>
#include <folly/futures/Future.h>
using namespace folly;
using namespace folly::coro;
int main() {
fmt::print("Result: {}\n", blockingWait(foo()));
}
Run Code Online (Sandbox Code Playgroud)
我用地址消毒剂编译了以下内容,以查看是否有任何悬空引用。
编辑:澄清的问题
根据cppreference:
当协程到达 co_return 语句时,它执行以下操作:
...
- 或为 co_return expr 调用 promise.return_value(expr),其中 expr 具有非 void 类型
- 以与创建它们相反的顺序销毁所有具有自动存储持续时间的变量。
- 调用 promise.final_suspend() 和 co_await 的结果。
因此,也许临时 lambda 的状态在返回结果之前实际上不会被破坏,因为foo
它本身是一个协程?
ASAN 错误:我假设在等待协程时“i”不存在
auto foo() -> …
Run Code Online (Sandbox Code Playgroud) 这个问题源于这个评论:C++20 协程的 Lambda 生命周期解释
关于这个例子:
auto foo() -> folly::coro::Task<int> {
auto task = []() -> folly::coro::Task<int> {
co_return 1;
}();
return task;
}
Run Code Online (Sandbox Code Playgroud)
所以问题是执行返回的协程是否foo
会导致UB。
“调用”成员函数(在对象的生命周期结束后)是 UB:http : //eel.is/c++draft/basic.life#6.2
...任何表示对象将位于或曾经位于的存储位置地址的指针都可以使用,但只能以有限的方式使用。[...] 程序有未定义的行为,如果:
[...]
-- 指针用于访问非静态数据成员或调用对象的非静态成员函数,或
但是,在这个例子中:
()
lambda 的生命周期仍然有效时调用 lambda的运算符()
)在之后的某个时间点恢复。此恢复是否被视为未定义行为?
所以 gnu 有 stdbuf 允许你修改命令的 I/O 流的缓冲。我需要相同的命令提示符功能,但我似乎找不到任何关于它的信息。
我只是尝试将程序的 stdout 和 stderr 输出到日志文件,而不进行缓冲(或者更确切地说,只是为了使它们同步并以与在控制台中显示的顺序相同的顺序显示)。
我是否只是错过了一些明显的命令或语法,或者我只是在 Windows 中不走运?
我正在研究一些我看到的处理0大小数组的代码.具体来说,它们用于动态分配结构大小的情况,例如https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
具体来说,这是Callgrind中的代码:
struct _EventGroup {
int size;
const char* name[0];
};
Run Code Online (Sandbox Code Playgroud)
我正在玩这个,在64位Red Hat上使用gcc 4.1.2,并注意到当name字段是一个指针时,sizeof函数返回整个struct _EventGroup的大小为8个字节.现在,如果我将其更改为:
struct _EventGroup {
int size;
const char name[0];
};
Run Code Online (Sandbox Code Playgroud)
我得到4个字节,因为gcc将0大小的数组标识为不占用空间,而int占用4个字节.那讲得通.如果我然后将其更改为:
struct _EventGroup {
int size;
const char* name;
};
Run Code Online (Sandbox Code Playgroud)
sizeof返回16个字节,因为char*在64位系统中占用8个字节,并且int必须填充到8个字节.这是有道理的.现在,如果我做最后一次改变:
struct _EventGroup {
const char* name[0];
};
Run Code Online (Sandbox Code Playgroud)
我得到0字节因为gcc检测到我的零大小数组.我要澄清的是在我提出的第一个案例中发生了什么.gcc为指向零大小数组的指针分配了多少空间?为什么?我问,因为这个代码看起来设计为内存分配效率很高,但是如果gcc检测到它指向基本上什么都没有,那么gcc要么指定大小为0字节,要么如果它被视为一个普通的指针.对齐将指示我使用原始结构获得4个字节或16个字节.为什么我得到8个字节?
我在C中有一个简单的向量实现,它包含一个void*数组.由用户来决定实际类型.
我想'保证'向量不会改变其内容,所以我将数据存储为:
Struct _Vector{
UInt32 used;
UInt32 size;
const void** arr;
};
Run Code Online (Sandbox Code Playgroud)
我不知道它是否被认为是"过度使用"我的常量正确性,但我尝试用我的访问器/修饰符来维持const正确性:
void vector_add(Vector *v, const void* const elem);
void vector_set(Vector *v, const UInt32 idx, const void* const elem);
Run Code Online (Sandbox Code Playgroud)
当我从向量中返回一个元素时,它是一个指向用户数据的指针,所以我让用户通过丢弃内部数组中的常量来修改指向的数据.
void* vector_get(const Vector *v, const UInt32 idx){
if ( idx >= v->used )
exitAtError("Vector","Array out of bounds");
return (void*)v->arr[idx];
}
Run Code Online (Sandbox Code Playgroud)
而不是返回const void*,而是返回void*.我的想法是在内部,我想确保我没有改变所指向的数据,但我不关心向量之外的数据会发生什么.
这被认为是const的正确用法吗?我认为在一个地方将数据声明为const是可以的,同时在其他地方将其变为可变.在阅读了许多声称永远不会抛弃constness的教条文章后,我不确定,如果它被丢弃,那么使用const是不合适的.
这是你不应该做的场景,但https://timsong-cpp.github.io/cppwp/class.cdtor#4指出:
成员函数,包括虚函数([class.virtual]),可以在构造或销毁([class.base.init])期间调用。
如果并行调用这些函数,这是否成立?也就是说,忽略竞争条件,如果A
正在构造过程中,并且frobme
在构造函数被调用之后的某个时间点被调用(例如在构造过程中),那仍然是定义的行为吗?
#include <thread>
struct A {
void frobme() {}
};
int main() {
char mem[sizeof(A)];
auto t1 = std::thread([mem]() mutable { new(mem) A; });
auto t2 = std::thread([mem]() mutable { reinterpret_cast<A*>(mem)->frobme(); });
t1.join();
t2.join();
}
Run Code Online (Sandbox Code Playgroud)
作为一个单独的场景,有人还向我指出, 的A
构造函数可以创建多个线程,这些线程可能会A
在构造完成之前调用成员函数函数,但是这些操作的顺序会更易于分析(您知道在构造函数中生成线程之后才会发生竞争)。
c++ constructor race-condition object-lifetime language-lawyer