我浪费了无数个小时来确定gcc的问题.我想用另一个编译器来测试我们的代码库,以寻找Clang可能错过的更多警告.我感到震惊的是,由于模板参数扣除失败,几乎有一半的项目停止编译.在这里,我试图将我的情况简化为最简单的代码.
#include <type_traits>
struct Foo
{ };
// This is a template function declaration, where second template argument declared without a default
template <typename T, typename>
void foo(const Foo & foo, T t);
// This is a template function definition; second template argument now has a default declared
template <typename T, typename = typename std::enable_if<1>::type>
void foo(const Foo & foo, T t)
{
}
int main(int argc, char ** argv)
{
foo(Foo{}, 1);
return 0;
} …Run Code Online (Sandbox Code Playgroud) 考虑一下这个C++ 11代码片段:
#include <iostream>
#include <set>
#include <stdexcept>
#include <initializer_list>
int main(int argc, char ** argv)
{
enum Switch {
Switch_1,
Switch_2,
Switch_3,
Switch_XXXX,
};
int foo_1 = 1;
int foo_2 = 2;
int foo_3 = 3;
int foo_4 = 4;
int foo_5 = 5;
int foo_6 = 6;
int foo_7 = 7;
auto get_foos = [=] (Switch ss) -> std::initializer_list<int> {
switch (ss) {
case Switch_1:
return {foo_1, foo_2, foo_3};
case Switch_2:
return {foo_4, foo_5};
case Switch_3: …Run Code Online (Sandbox Code Playgroud) 在libc++的实现中std::function,如果要擦除其类型的函数对象足够小以适合 SBO,则移动操作将复制它,而不是移动它。然而,并不是每个堆栈内存占用较小的对象都适合复制。为什么要复制而不是移动?
使用 Clang 考虑这个示例(使用shared_ptr它是因为它具有引用计数):
https://wandbox.org/permlink/9oOhjigTtOt9A8Nt
中的语义与使用显式副本test1()的语义相同。帮助我们看到这一点。test3()shared_ptr
另一方面,GCC 的行为是合理且可预测的:
https://wandbox.org/permlink/bYUDDr0JFMi8Ord6
两者都是标准允许的。std::function要求函数可复制,移出的对象处于未指定状态,等等。为什么要这么做?同样的推理也适用于std::map:如果键和值都是可复制的,那么为什么不每当有人std::movesa时就制作一个新副本std::map?这也符合标准的要求。
根据cppreference.com 的说法,应该有一个举动,并且应该是目标。
这个例子:
#include <iostream>
#include <memory>
#include <functional>
#include <array>
#include <type_traits>
void test1()
{
/// Some small tiny type of resource. Also, `shared_ptr` is used because it has a neat
/// `use_count()` feature that will allow us to see what's going on behind the 'curtains'.
auto foo …Run Code Online (Sandbox Code Playgroud) 说真的,什么都没有.有从隐式转换std::string到std::string_view,它不是认为是不安全的.如果程序员不小心,这肯定会导致许多悬空引用.
在另一方面,他们已经解雇的隐式转换从std::string_view到std::string使用相同的说法,但在完全相反的方式:因为程序员可能是不小心的.
很可爱的是,他们创建了一个原始const char*指针的替代品,同时使它变得非常混乱并剥离了骨头:
const char*- > std::string:好的std::string_view- > std::string:NOPEstd::string= const char*:好的std::string= std::string_view:好的std::string+ = const char*:好的std::string+ = std::string_view:好的const char*+ std::string:好的std::string_view+ std::string:NOPEstd::string+ const char*:好的我的问题是关于C++ 17:http://en.cppreference.com/w/cpp/string/basic_string_view/basic_string_view
从std :: basic_string到std :: basic_string_view的隐式转换的警告是什么,它不包含在后者的接口中?
我相信这会大大改善这门课程.特别是比较运算符族,也不接受std :: string既不是lhs也不是rhs.
库基础知识TS规范中有这样的转换:http://en.cppreference.com/w/cpp/experimental/basic_string_view/basic_string_view
这个问题是为什么它被删除.或者更不被采纳.
当切换到c ++ 17并用std::optional标准解决方案替换自定义解决方案时,检测到clang 5的一个非常奇怪和意外的行为.出于某种原因,emplace()由于对std::is_constructible参数类的特征的错误评估而被禁用.
在复制之前必须满足一些特定的前提条件:
#include <optional>
/// Precondition #1: T must be a nested struct
struct Foo
{
struct Victim
{
/// Precondition #2: T must have an aggregate-initializer
/// for one of its members
std::size_t value{0};
};
/// Precondition #3: std::optional<T> must be instantiated in this scope
std::optional<Victim> victim;
bool foo()
{
std::optional<Victim> foo;
// An error
foo.emplace();
/// Assertion is failed
static_assert(std::is_constructible<Victim>::value);
}
};
Run Code Online (Sandbox Code Playgroud)
更改任何前提条件并按预期编译.标准中是否存在一些未知的不一致性,使得clang在符合要求时拒绝此代码?
作为旁注:GCC 7.1 …
我们已经在生产中使用asio多年了,最近我们已经达到一个关键点,当我们的服务器加载到足以注意到一个神秘的问题.
在我们的体系结构中,独立运行的每个独立实体都使用个人strand对象.一些实体可以执行长时间的工作(从文件读取,执行MySQL请求等).显然,这项工作是在用钢绞线包裹的处理人员中进行的.所有听起来都很漂亮,应该完美无缺,直到我们开始注意到一些不可能的事情,比如计时器应该在它们应该到期后几秒钟到期,即使线程正在"等待工作"并且工作停止没有明显的原因.看起来像是在一条链内进行的长时间工作对其他不相关的股线产生了影响,而不是全部,但大多数.
花了不少时间来查明问题.轨道导致的方式strand创建对象:strand_service::construct(这里).
出于某种原因,开发人员决定strand实施数量有限.这意味着一些完全不相关的对象将共享一个实现,因此会因此受到瓶颈.
在独立(非增强)asio库中,正在使用类似的方法.但是,不是共享实现,每个实现现在都是独立的,但可以mutex与其他实现共享一个对象(这里).
这是什么一回事呢?我从未听说过系统中互斥锁数量的限制.或任何与其创建/破坏相关的开销.虽然最后一个问题可以通过回收互斥体而不是破坏它们来轻松解决.
我有一个最简单的测试用例来说明性能下降有多么戏剧性:
#include <boost/asio.hpp>
#include <atomic>
#include <functional>
#include <iostream>
#include <thread>
std::atomic<bool> running{true};
std::atomic<int> counter{0};
struct Work
{
Work(boost::asio::io_service & io_service)
: _strand(io_service)
{ }
static void start_the_work(boost::asio::io_service & io_service)
{
std::shared_ptr<Work> _this(new Work(io_service));
_this->_strand.get_io_service().post(_this->_strand.wrap(std::bind(do_the_work, _this)));
}
static void do_the_work(std::shared_ptr<Work> _this)
{
counter.fetch_add(1, std::memory_order_relaxed);
if (running.load(std::memory_order_relaxed)) {
start_the_work(_this->_strand.get_io_service());
}
}
boost::asio::strand _strand;
};
struct BlockingWork
{ …Run Code Online (Sandbox Code Playgroud) 不是std::span设计为轻量参考的子区域std::vector/ std::array/普通数组和相似吗?它不应该在其 API 中也包含比较运算符,以与它们保持一致吗?排除背后的原因是什么?
注意:通过比较运算符,我的意思是完整的集合 ( <, <=, ...) 或宇宙飞船<=>
在某个地方,有一次我读到了关于内存栅栏(障碍物)的内容.据说内存栅栏会导致多个CPU内核之间的缓存同步.
所以我的问题是:
操作系统(或CPU本身)如何知道需要同步哪些内核?
它是否同步所有CPU核心的缓存?
如果对(2)的回答为"是"并假设同步操作不便宜,那么使用内存栅栏是否会减慢我的应用程序未使用的内核?例如,如果我的8核CPU上运行单线程应用程序,它是否会降低CPU的所有其他7个内核的速度,因为某些高速缓存行必须与所有这些内核同步?
以上问题是完全无知的,围栏的工作完全不同吗?
我很迷惑.实现如何才能知道类型是否仅在运行时是原子的?
c++ ×9
c++11 ×3
c++17 ×3
atomic ×2
c++20 ×2
boost-asio ×1
c ×1
clang ×1
cpu ×1
gcc ×1
lambda ×1
libc++ ×1
std ×1
std-function ×1
std-span ×1
stdoptional ×1
string-view ×1
templates ×1