如果类 S 是一个聚合或者至少具有一个普通的合格构造函数和一个普通的、未删除的析构函数,则它是隐式生命周期类。
并且可以使用 malloc 创建隐式生命周期对象。请参阅此示例。
#include <cstdlib>
struct X { int a, b; };
X* MakeX()
{
// One of possible defined behaviors:
// the call to std::malloc implicitly creates an object of type X
// and its subobjects a and b, and returns a pointer to that X object
X* p = static_cast<X*>(std::malloc(sizeof(X)));
p->a = 1;
p->b = 2;
return p;
}
Run Code Online (Sandbox Code Playgroud)
但struct A {std::string s;};也是一个总和。但这会产生一个异常,正如我所期望的,因为对 s 的赋值将首先破坏 …
在查看涉及CPU高速缓存大小之外的大量访问的性能问题时,我做了一个测试,它以增加的块大小"随机"地对存储器访问进行"随机"调整.我看到了L1,2,3 Cache块大小的预期变化,但是很惊讶地看到访问时间继续减少远远超出缓存功能.
例如,从256MB块到4GB块的访问时间减少了一半.从每uS 50次读/写到每uS 25次读/写.减少继续到系统内存限制.我为其他应用程序和操作系统留下了8GB(或4GB)的额外费用.
L3缓存是8MB,因此我预计对较大的块大小的缓存影响非常小.
该算法使用原始多项式来"随机"寻址每个64位字.这有效地以相当随机的方式访问地址,但确保除了0索引之外的所有地址每次访问只被访问一次.经过足够数量的通过后,每个通过大约一秒钟,结果列表.
我无法解释这个持续的访问时间减少远远超出缓存限制.有什么解释吗?
以下是3台不同Windows 10机器的结果:
| Memory block (bytes)
| | 64 bit words incremented per us
-- desktop I7 980 24GB -- -- Surface Book 16GB -- --HP Envy 8GB --
128 544.80 128 948.43 128 774.22
256 554.01 256 1034.15 256 715.50
512 560.12 512 993.28 512 665.23
1.02k 512.93 1.02k 944.24 1.02k 665.19
2.05k 527.47 2.05k 947.09 2.05k 664.84
4.10k 517.41 4.10k 931.48 4.10k 664.94
8.19k 517.55 8.19k 939.61 8.19k 666.40
16.38k …Run Code Online (Sandbox Code Playgroud) 在测试const对象成员的处理时,我在 clang 中遇到了这个明显的错误。该代码可在 msvc 和 gcc 中运行。然而,该错误仅出现在非常量中,这无疑是最常见的用途。我做错了什么还是这是一个真正的错误?
https://godbolt.org/z/Gbxjo19Ez
#include <string>
#include <memory>
struct A
{
// const std::string s; // Oddly, declaring s const compiles
std::string s;
constexpr A() = default;
constexpr A(A&& rh) = default;
constexpr A& operator=(A&& rh) noexcept
{
std::destroy_at(this);
std::construct_at(this, std::move(rh));
return *this;
}
};
constexpr int foo()
{
A i0{}; // call ctor
// Fails with clang. OK msvc, gcc
// construction of subobject of member '_M_local_buf' of union with no active member …Run Code Online (Sandbox Code Playgroud) 我想创建一个const std::vector<T>可以存储用户代码可以访问但不能(轻松)修改的可更新值的值。这样做有几个优点。矢量对象(但不能更改其内容)无法更改。因此,如果有人稍后决定添加新元素或其他可能导致悬空引用的操作,则可以建立对向量中条目的引用,而不会产生悬空引用。而且,由于它是一个完整的 const 对象,因此即使placement-new没有 UB 和/或编译器投诉,也无法对其进行修改。
这似乎是可能的,因为虽然向量对象是 const,但Ts 不是且必须存储为非常量。尝试将它们存储为 const 会产生以下错误:
C++ 标准禁止 const 元素的容器,因为
allocator<const T>其格式不正确。
看到这个
因此,由于T不是 const,而是仅在访问时才显示为 const,因此似乎可以通过使用 aconst_cast来删除 const 来访问和更新它们。
我还没有遇到过这种可修改 const 向量的使用,但它似乎是相当合法的。我错过了什么吗?
constexpr以下是包含额外 UB 测试的代码:
#include <vector>
#include <iostream>
constexpr int foo()
{
const std::vector<int> v{ 1,2,3 };
const int& rci = v[0]; // A const ref to v[0] is ok
int& ri = const_cast<int&>(v[0]); // A ref to v[0] as a …Run Code Online (Sandbox Code Playgroud) 使用std::array我可以将数组本身及其对象声明为 const。
const std::array<const int,2> a {1,2};
Run Code Online (Sandbox Code Playgroud)
然而,如果我正确地阅读了标准,像这样的声明只会将数组元素声明为 const。看到这个
const int a[2] {1,2};
Run Code Online (Sandbox Code Playgroud)
这很重要的原因是,在这些情况下a,如果完整的对象是 const,那么 UB 就可以更改任何子对象。如果只有子对象,如a[0]const,那么它们可以通过“透明替换”进行修改,并且它不是 UB。这是自 c++20 起 basic.life 的新变化。看到这个。从数组的定义中也可以清楚地看出,数组元素是子对象。看到这个
例如,如果完整对象(总数组)不是 const,则这将是合法的。
std::construct_at(&a[0], 5);
Run Code Online (Sandbox Code Playgroud)
std::array那么除了使用包装器来声明完整的数组const之外还有什么方法吗?
voidify()用于c++20 中引入的specialized.algorithms 的各种构造函数中。我不清楚它应该做什么。其给出为:
template<class T>
constexpr void* voidify(T& obj) noexcept {
return const_cast<void*>(static_cast<const volatile void*>(addressof(obj)));
}
Run Code Online (Sandbox Code Playgroud)
将地址转换为指向 a 的指针const volatile void,然后又转换回指向 a 的指针的原因是什么void?
我猜测它与以某种方式告诉编译器的优化器有关,分配给它最终寻址的内存的对象应该丢弃它所知道的所有先前的缓存(读取或写入)。但我在任何地方都找不到任何关于它应该如何工作的描述。
注意:这个问题与相关的问题不同,但这里的问题不同,这个答案并没有解决这个问题。
这个问题是为什么人们不能简单地使用static_cast<void*>,答案显然是正确的,static_cast不允许放弃 const 但可以添加 cv。
更新:刚刚将 MSVC 编译器更新到 17.4.5。MSVC 现在表示 和A是Az发布模式下兼容的类型,但当std::vector包含在结构中时,在调试模式下不兼容。真奇怪。可能与向量的大小差异有关。Release 模式下的向量由预期的 3 个指针组成。在调试模式下,它通过一个附加指针进行扩展,该指针似乎是为了某种附加使用验证而添加的。
根据布局兼容类型的描述,结构体 A 和结构体 Az 应该符合资格,因为结构体内容是相同的。
如果 T1 和 T2 是相同类型、布局兼容枚举或布局兼容标准布局类类型,则两种类型 cv1 T1 和 cv2 T2 是布局兼容类型。
Clang 无法编译,因为std::is_layout_compatible未实现。对于 和vector,intgcc 可以工作并返回 true,is_layout_compatible而 MSVC 在发布模式下返回 true,但在调试模式下返回 false。
#include <memory>
#include <iostream>
#include <vector>
#include <type_traits>
struct Az {
std::vector<int> v;
int i;
};
struct A {
std::vector<int> v;
int i;
};
int …Run Code Online (Sandbox Code Playgroud) 注意:此错误仅在发布和调试模式下的 x64 项目中出现。
std::chrono使用 VC2019 的这段代码出现警告级别为 3 的奇怪警告。这是一段处理命令行标志的精简代码。我已经删除了大部分与问题无关的内容。
#if 1 // enable bug
#include <chrono> // excluding this also eliminates chrono warnings
using CorrectedIntType=int;
#else
using CorrectedIntType=size_t;
#endif
#include <iostream>
#include <vector>
#include <string>
#include <type_traits>
using std::vector;
using std::string;
namespace {
void fixup(const std::string& argcmd, std::string& arg) { arg = argcmd; }
template<class T>
void procVal(std::vector<std::string>& arglist, CorrectedIntType idx, T& arg)
{
fixup(arglist[idx], arg);
arglist.erase(arglist.begin() + idx);
}
template<class T, class ...TA>
void procVal(std::vector<std::string>& arglist, CorrectedIntType idx, T& …Run Code Online (Sandbox Code Playgroud) const 向量无法修改,因为它是 const 对象。所以插入、追加、删除都是不允许的。然而,它的内容不是该对象的一部分,而是由该对象拥有。举个类似的例子:
int* const p = new int[10]{1,2,3,4};
Run Code Online (Sandbox Code Playgroud)
p是一个 const 对象,拥有可以修改的非常量数据:p[1]=5;
Vector 的operator[]条件是向量是否为 const,如果是,则返回 aconst int&但如果基础值不是 const,则删除 const 的 const 强制转换应该是合法的。
为了测试这一点,我编写了以下程序:
#include <vector>
constexpr int foo()
{
const std::vector<int> v{ 1,2,3 };
const int a[3]{ 1,2,3 };
*const_cast<int*>(&v[1]) = 21;
// However, this should fail and does on GCC and CLANG
//*const_cast<int*>(&a[1]) = 21;
return v[1];
}
int main()
{
constexpr int sb21 = foo();
const std::vector<int> v{ 1,2,3 };
*const_cast<int*>(&v[1]) …Run Code Online (Sandbox Code Playgroud) 我在使用此代码的 clang 中遇到了编译错误。我没有发现它有任何问题,它可以在 msvc 和 gcc 中工作。我错过了什么还是它是一个错误?
#include <iostream>
#include <string>
#include <type_traits>
constexpr bool do_tests()
{
// prints error message at runtime if test is false
auto verify = [](bool test, std::string message = "error") {
if (!std::is_constant_evaluated() && !test)
std::cout << message << '\n';
return test;
};
return verify(1 == 1, "test");
};
int main()
{
constexpr bool b = do_tests();
std::cout << b << '\n';
}
Run Code Online (Sandbox Code Playgroud)
来自 clang 的莫名其妙的错误消息:
basic_string.h:356:10:注意:在常量表达式中不允许对没有活动成员的联合体的成员“_M_local_buf”进行赋值
---- 开始编辑 ----
用户@user17732522 指出调用UB 的缺陷是因为pop_back()根据库文档使使用的引用无效vector。当发生这种情况时,不需要 constexpr 求值来检测它,因为它不是 C++ 核心的一部分。
然而,@user17732522 也指出的修复很简单。替换这两行连续代码的出现:
v.pop_back();
v.emplace_back(...);
Run Code Online (Sandbox Code Playgroud)
用这两行:
std::destroy_at(&v[0]); // optional since A has a trivial destructor
std::construct_at<A, int>(&v[0], ...);
Run Code Online (Sandbox Code Playgroud)
---- 开始原创 ----
虽然引用在 destroy_at 上失效,但它们会被 construct_at 自动具体化。请参阅: https: //eel.is/c++draft/basic#life-8,
众所周知,您不能修改 const 值,除非它们最初是非 const。但似乎有一个例外。包含具有 const 成员的对象的向量。
就是这样:
#include <vector>
#include <iostream>
struct A {
constexpr A(int arg) : i{ arg } {}
const int i;
};
int main()
{
std::vector<A> v;
v.emplace_back(1); // vector of one A initialized …Run Code Online (Sandbox Code Playgroud) 可以比较指向类成员变量的指针,结果取决于声明顺序。请参阅规范例如,编译器资源管理器中的此示例有效并返回 true (1):
struct A {
int a0 = 1;
int a1 = 2;
};
consteval int foo()
{
A a;
int* p1 = &a.a0;
int* p2 = &a.a1;
return p2 > p1;
}
int main()
{
return foo();
}
Run Code Online (Sandbox Code Playgroud)
因此,人们会期望它p2-p1会返回指针之间的距离(以 int 对象为单位)。它在运行时执行。编译器浏览器
struct A {
int a0 = 1;
int a1 = 2;
};
int foo()
{
A a;
int* p1 = &a.a0;
int* p2 = &a.a1;
return p2 - p1;
} …Run Code Online (Sandbox Code Playgroud)