注意:我们在这里谈论(据称)符合C++ 98的编译器.这不是C++ 11的问题.
我们在其中一个编译器中有一个奇怪的行为,我们不确定这是否正常或者这是否是编译器错误:
// This struct has a default constructor
struct AAA
{
AAA() : value(0) {}
int value ;
} ;
// This struct has a member of type AAA and an array of int, both surrounded
// by ints
struct BBB
{
int m_a ;
AAA m_b ;
int m_c ;
int m_d[42] ;
} ;
Run Code Online (Sandbox Code Playgroud)
当BBB初始化时:
BBB bbb = {0} ;
Run Code Online (Sandbox Code Playgroud)
我们期望BBB的所有POD成员(包括m_d,整数数组)被零初始化,并且要构建BBB的所有非POD成员.
这适用于AIX的本机编译器,在Linux/GCC-3.4上,在Windows/VisualC++上......但不适用于Solaris/SunStudio,其中只有非数组成员被零初始化.
我们在C++ 98标准(草案文档)中进行了一些研究,在那里我们发现了以下内容:
[12.6.1 - 2]
当聚合(无论是类还是数组)包含类类型的成员并由大括号括起的初始化列表(8.5.1)初始化时,每个这样的成员都由相应的赋值表达式进行复制初始化(见8.5).如果初始化列表中的初始值设定项少于聚合的成员,则未明确初始化的每个成员都应默认初始化(8.5).
然后:
[8.5 - 5]
对 …
示例代码是:
#include <unordered_map>
int main() {
std::unordered_map<int, std::pair<int, int>> map;
map.emplace(1, {1, 1});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
哪里emplace()有签名,如:
template <class... _Args>
pair<iterator, bool> emplace(_Args&&... __args);
Run Code Online (Sandbox Code Playgroud)
该gcc说的功能expectes 0参数- 2提供的.该clang说,函数需要1个参数- 2提供的.
我甚至不明白 - 这段代码有什么问题?
c++ variadic-functions compiler-bug c++11 list-initialization
以下代码使用GCC 4.9.2编译,但不与Clang 3.5.0编译:
#include <string>
class Foo
{
public:
explicit operator std::string() const;
};
std::string bar{Foo{}}; // Works in g++, fails in clang++
std::string baz(Foo{}); // Works in both
Run Code Online (Sandbox Code Playgroud)
clang ++说:
foo.cpp:9:13: error: no matching constructor for initialization of 'std::string'
(aka 'basic_string<char>')
std::string bar{Foo{}};
^ ~~~~~~~
...: note: candidate constructor not viable: no known conversion from 'Foo' to
'const std::basic_string<char> &' for 1st argument
basic_string(const basic_string& __str);
^
Run Code Online (Sandbox Code Playgroud)
奇怪的是,如果std::string被替换为原始类型,它就可以工作int.
我试图使用64位积分作为位图,并原子地获取/释放各个位的所有权.
为此,我编写了以下无锁代码:
#include <cstdint>
#include <atomic>
static constexpr std::uint64_t NO_INDEX = ~std::uint64_t(0);
class AtomicBitMap {
public:
static constexpr std::uint64_t occupied() noexcept {
return ~std::uint64_t(0);
}
std::uint64_t acquire() noexcept {
while (true) {
auto map = mData.load(std::memory_order_relaxed);
if (map == occupied()) {
return NO_INDEX;
}
std::uint64_t index = __builtin_ctzl(~map);
auto previous =
mData.fetch_or(bit(index), std::memory_order_relaxed);
if ((previous & bit(index)) == 0) {
return index;
}
}
}
private:
static constexpr std::uint64_t bit(std::uint64_t index) noexcept {
return std::uint64_t(1) << index;
}
std::atomic_uint64_t mData{ …Run Code Online (Sandbox Code Playgroud) 我偶然发现了一种情况,库std::vector<T>使用用户提供的比较对象对容器(例如)进行排序。对于一种特定情况,用户实际上不想对容器进行排序,但排序是无条件发生的。
因此,为了尽量避免这种情况,我想尝试使用根据元素地址排序的比较对象。等价地,我们有:
std::vector nums{1, 5, 4};
auto cmp = [](auto& a, auto& b) { return &a < &b; };
std::sort(nums.begin(), nums.end(), cmp);
Run Code Online (Sandbox Code Playgroud)
这是“有效的”,因为std::vector<T>元素以与向量中元素相同的顺序存储在(连续)内存位置中。最终结果是,nums即使在排序之后,向量似乎也没有被改变。
但是,一旦我替换std::vector<T>为std::array<T, N>,我就会遇到分段冲突(请参阅https://gcc.godbolt.org/z/9srehdbhG)。
我的第一个想法是我违反了https://en.cppreference.com/w/cpp/algorithm/sort中列出的类型要求:
RandomIt必须满足ValueSwappable和LegacyRandomAccessIterator的要求。- 解除引用的类型必须满足MoveAssignable和MoveConstructible
RandomIt的要求。Compare必须满足Compare的要求。
我的假设是元素的地址在整个排序过程中保持稳定 - 这几乎肯定是错误的。
那么,std::sort()我违反了哪些要求/先决条件?
#include <cstddef>
template<typename T, T... Is>
struct Bar { };
template<size_t... Is>
using Baz = Bar<size_t, Is...>;
struct Foo {
template<size_t... Is>
void NoAlias(Bar<size_t, Is...>) { }
template<size_t... Is>
void Alias(Baz<Is...>) { }
};
template<typename T, T... Is>
void foo(Bar<T, Is...>) { }
template<size_t... Is>
void bar(Bar<size_t, Is...>) { }
int main() {
// All these work fine
foo(Bar<size_t, 4, 2>());
foo(Baz<4, 2>());
bar(Bar<size_t, 4, 2>());
bar(Baz<4, 2>());
Foo().NoAlias(Bar<size_t, 4, 2>());
Foo().NoAlias(Baz<4, 2>());
// But these two give error on …Run Code Online (Sandbox Code Playgroud) 以下代码不能用 gcc 或 clang 编译。
template<class T>
class foo{};
template<class T>
class template_class_with_struct
{
void my_method() {
if(this->b.foo < 1);
};
struct bar
{
long foo;
} b;
};
Run Code Online (Sandbox Code Playgroud)
错误信息是
error: type/value mismatch at argument 1 in template parameter list for 'template<class T> class foo'
8 | if(this->b.foo < 1);
Run Code Online (Sandbox Code Playgroud)
该错误是由模板类 foo 引起的。当编写 <= 而不是 < 1 时,它也会编译。
任何提示赞赏?
CompilerExplorer 链接https://godbolt.org/z/v6Tygo
有谁知道这是什么类型的UB吗?使用 MSVC 19.29.30148 构建时,以下代码在jthread销毁时死锁,有时在 std::cout 之后死锁,有时在之前死锁。这在某种程度上与 thread_local 有关,但我看不出问题是什么。它似乎在其他编译器和平台下工作得很好。
#include <thread>
#include <memory>
#include <iostream>
int main(void)
{
std::thread t2(
[&] {
thread_local std::jthread asd([] {
std::cout << "ASD" << std::endl;
});
});
if (t2.joinable()) { t2.join(); }
}
Run Code Online (Sandbox Code Playgroud)
更新:在静态和动态运行时均可重现
特别是Clang 3.6.0,目前由Coliru主持.
所有这些片段都来自:
int main() {
foo();
std::cout << "\n----\n";
foo(1, 2, 3);
}
Run Code Online (Sandbox Code Playgroud)
以下代码:
template <class... Args>
void foo(Args... args) {
std::cout << ... << args;
}
Run Code Online (Sandbox Code Playgroud)
触发以下编译错误:
main.cpp:7:17: error: expected ';' after expression
std::cout << ... << args;
^
;
main.cpp:7:15: error: expected expression
std::cout << ... << args;
^
Run Code Online (Sandbox Code Playgroud)
所以我试着在表达式周围添加括号:
(std::cout << ... << args);
Run Code Online (Sandbox Code Playgroud)
它有效,但会触发警告:
main.cpp:7:6: warning: expression result unused [-Wunused-value]
(std::cout << ... << args);
^~~~~~~~~
main.cpp:11:5: note: in instantiation of function template specialization 'foo<>' …Run Code Online (Sandbox Code Playgroud) 在以下示例中:
struct Foo {
[[maybe_unused]] int member = 1;
void bar() {
[[maybe_unused]] int local = 0;
}
};
int main(int argc, char* argv[]) {
Foo f{};
f.bar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
GCC 发出警告,其中 Clang 和 MSVC 没有:
warning: 'maybe_unused' attribute ignored [-Wattributes]
[[maybe_unused]] int member = 1;
Run Code Online (Sandbox Code Playgroud)
据我所知,这应该是合法的(并且不会被编译器忽略)。根据标准:
10.6.7 可能未使用的属性 [dcl.attr.unused]
...
2. 该属性可以应用于类的声明、typedef-name、变量、非静态数据成员、函数、枚举,或枚举器。
...
我讨厌在“编译器错误”锤子上摇摆不定,但我不确定在这种情况下还有什么可能。
有没有人有任何见解?