小编Nia*_*las的帖子

C++标准委员会是否打算在C++ 11中unordered_map破坏它所插入的内容?

我失去了三天的生命追踪一个非常奇怪的错误,其中unordered_map :: insert()会破坏你插入的变量.这种非常明显的行为只发生在最近的编译器中:我发现clang 3.2-3.4和GCC 4.8是唯一能够证明这个"特性"的编译器.

这是我的主代码库中的一些简化代码,用于演示此问题:

#include <memory>
#include <unordered_map>
#include <iostream>

int main(void)
{
  std::unordered_map<int, std::shared_ptr<int>> map;
  auto a(std::make_pair(5, std::make_shared<int>(5)));
  std::cout << "a.second is " << a.second.get() << std::endl;
  map.insert(a); // Note we are NOT doing insert(std::move(a))
  std::cout << "a.second is now " << a.second.get() << std::endl;
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我和大多数C++程序员一样,希望输出看起来像这样:

a.second is 0x8c14048
a.second is now 0x8c14048
Run Code Online (Sandbox Code Playgroud)

但是对于clang 3.2-3.4和GCC 4.8,我得到了这个:

a.second is 0xe03088
a.second is now 0
Run Code Online (Sandbox Code Playgroud)

这可能毫无意义,直到您仔细检查http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/中unordered_map :: insert()的文档,其中重载号为2:

template <class P> pair<iterator,bool> …
Run Code Online (Sandbox Code Playgroud)

c++ standards gcc clang c++11

113
推荐指数
2
解决办法
6285
查看次数

为什么在Herb Sutter的CppCon 2014演讲(回归基础:现代C++风格)中不推荐使用setter成员函数?

在Herb Sutter的CppCon 2014谈话回归基础:现代C++风格他在幻灯片28(幻灯片的网络副本在这里)上引用了这种模式:

class employee {
  std::string name_;
public:
  void set_name(std::string name) noexcept { name_ = std::move(name); }
};
Run Code Online (Sandbox Code Playgroud)

他说这是有问题的,因为当用临时调用set_name()时,noexcept-ness不强(他使用短语"noexcept-ish").

现在,我在我最近的C++代码中使用了上述模式,主要是因为它节省了我每次都输入两个set_name()的副本 - 是的,我知道每次强制复制构造都会有点效率低下,但是,嘿,我是一个懒惰的人.然而Herb的短语"这个noexcept是有问题的 "让我担心,因为我没有在这里得到问题:std :: string的移动赋值运算符是noexcept,因为它的析构函数,所以上面的set_name()似乎保证noexcept.我确实看到编译器 set_name()之前抛出了一个潜在的异常,因为它准备了参数,但我很难看到它有问题.

后来在幻灯片32上Herb明确指出上面是一个反模式.有人可以向我解释为什么我一直懒惰地编写糟糕的代码?

c++ stl c++11

62
推荐指数
3
解决办法
5550
查看次数

您将如何从用户模式代码中一般性地检测缓存行关联性?

我正在为valgrind中的cachegrind/callgrind工具整理一个小补丁,它将使用完全通用的代码,CPU指令和缓存配置自动检测(现在只有x86/x64自动配置,而其他架构不提供CPUID类型配置为非特权代码).此代码需要完全在非特权上下文中执行,即纯用户模式代码.它还需要可以在非常不同的POSIX实现中移植,因此grokking/proc/cpuinfo不会这样做,因为我们的目标系统之一没有这样的东西.

检测CPU的频率,高速缓存的数量,它们的大小,甚至高速缓存行大小都可以使用100%通用POSIX代码完成,该代码没有任何特定于CPU的操作码(只是很多合理的假设,例如添加两个数字在一起,如果没有内存或寄存器依赖性停顿,可能会在一个周期内执行).这部分相当简单.

什么不是那么简单,为什么我问StackOverflow,是如何检测给定缓存的缓存行关联性?关联性是缓存中可以包含来自主内存的给定缓存行的位数.我可以看到可以检测到L1缓存关联性,但L2缓存?当然L1关联性会受到影响吗?

我很欣赏这可能是一个无法解决的问题.但我把它扔到StackOverflow上,并希望有人知道我不知道的事情.请注意,如果我们在这里失败,我将简单地以四方式的关联性默认值进行硬编码,假设它不会对结果产生巨大影响.

谢谢,
尼尔

c valgrind cpu-architecture cpu-cache

17
推荐指数
1
解决办法
2626
查看次数

为什么std :: atomic initialisation没有原子释放,所以其他线程可以看到初始值?

提议的boost :: concurrent_unordered_map的线程清理过程中出现了一些非常奇怪的东西,并在这篇博客文章中进行了叙述.简而言之,bucket_type如下所示:

  struct bucket_type_impl
  {
    spinlock<unsigned char> lock;  // = 2 if you need to reload the bucket list
    atomic<unsigned> count; // count is used items in there
    std::vector<item_type, item_type_allocator> items;
    bucket_type_impl() : count(0), items(0) {  }
    ...
Run Code Online (Sandbox Code Playgroud)

然而线程消毒者声称在bucket_type的构造和它的第一次使用之间存在竞争,特别是当加载计数原子时.事实证明,如果你通过它的构造函数初始化std :: atomic <>,那么初始化不是原子的,因此内存位置不是原子释放的,因此对其他线程不可见,这是违反直觉的,因为它是一个原子,并且大多数原子操作默认为memory_order_seq_cst.因此,您必须在构造之后显式执行发布存储,以使用其他线程可见的值初始化原子.

是否有一些非常迫切的原因,为什么std :: atomic与值消耗构造函数不会使用发布语义初始化自己?如果没有,我认为这是一个库缺陷.

编辑:乔纳森的回答是,为什么在历史上较好,但ecatmur的回答环节对此事阿拉斯泰尔的缺陷报告,以及它是如何通过简单地添加注释说建设没有提供可视性,其他线程关闭.因此,我将奖励ecatmur.感谢所有回复的人,我认为要求一个额外的构造函数的方式很明显,它至少会在文档中脱颖而出,值得使用构造函数.

编辑2:我最终将此作为C++语言中的缺陷与委员会一起提出,并且并发部分主持人Hans Boehm认为这不是问题,原因如下:

  1. 2014年没有现有的C++编译器将消费视为与获取不同.正如您将永远不会,在现实世界的代码中,将原子传递给另一个线程而不经过一些释放/获取,原子的初始化将使用原子对所有线程可见.我觉得这很好,直到编译器赶上来,在此之前,Thread Sanitiser会对此发出警告.

  2. 如果你做不匹配的消耗,获取释放像我(我使用的版本,里面锁/消耗,外锁原子,以推测避免释放获取自旋锁的地方是不必要的),那么你是一个大足够的男孩知道你必须在施工后手动储存释放原子.这可能是一个公平的观点.

c++ multithreading stl atomic c++11

17
推荐指数
3
解决办法
1155
查看次数

如果类型为noexcept,C++ 11 STL中的哪些算法和容器可以更快?

关于使用noexcept需要多少关注的问题,正在进行一场辩论.我们都知道noexcept对于编译器的优化器并没有真正做大量的事情,除了外部定义的代码,编译器否则必须假设它可以抛出,因为它无法知道它的实现,因此标记事物的唯一真正的其他性能优势noexcept用于使用std :: move_if_noexcept <>的代码,假定它主要是STL容器及其算法.

因此,该评估将是这样的:你不能使用noexcept,除非:

  1. extern函数和类,其中编译器不知道可调用的实现.

  2. 移动构造函数,移动赋值运算符并交换可能包含在STL容器中的任何类型.

  3. 否则不要担心.

这是一个公平的评估吗?STL中还有其他地方可以产生更优化的代码吗?如果是这样,哪个STL实现是这个,什么需要标记为no,除了它工作,以及什么性能的好处导致(更少的内存分配,更低的复杂性)?

编辑:使CashCow建议更改措辞.

c++ algorithm stl noexcept c++11

13
推荐指数
1
解决办法
587
查看次数

如何使用libclang检测枚举和范围枚举之间的区别?

我一直在使用优秀的C接口libclang(http://clang.llvm.org/doxygen/group__CINDEX.html)编写C++ AST解析器.不幸的是,在C++ 11作用域枚举和旧式枚举之间似乎没有消歧:两者都有一个游标类型CXCursor_EnumDecl和一个类型CXType_Enum即相同.

我试过拜访孩子,看他们的父母类型是否不同 - 遗憾的是没有.我试过要求底层类型,我得到两个整数.我已经检查了Enum之后声明的所有项目,看看是否可能出现旧式枚举的bind或typedef,再次没有明显区别.

我开始认为我必须遗漏一些东西.我是否必须使用代码完成API来确定它是哪种枚举?

abstract-syntax-tree c++11 libclang

8
推荐指数
1
解决办法
362
查看次数

在C++中检测constexpr size()成员函数14

我有一些通用代码,它们想知道何时传递了一系列对象,这些对象的数量在编译时是已知的,因为它可以选择另一种算法策略.为此,我尝试编写一个has_constexpr_size(T)constexpr函数,如下所示,它试图探测T的size()成员函数,看它是否可以作为constexpr执行.

请注意,与通常的"我可以检测到constexpr执行上下文吗?"存在一个关键区别.问题是因为一些STL容器array<T> 总是提供constexpr-available size()函数,而其他STL容器就像initializer_list<T>获得constexpr-available size()函数一样,当且仅当初始化列表本身是constexpr时(因为实现依赖于内部指针对,那些需要是constexpr用于size()拥有all-constexpr输入).has_constexpr_size(T)因此,该函数采用T被测试类型的实例,以便它可以检测两种情况.

这是一个测试用例:

#include <array>
#include <type_traits>
#include <utility>
#include <vector>

namespace type_traits
{
  namespace detail
  {
    template <size_t N> struct Char
    {
      char foo[N];
    };
    template <class T> constexpr inline Char<2> constexpr_size(T &&v) { return (v.size(), true) ? Char<2>() : throw 0; }
    template <class T> inline Char<1> constexpr_size(...) { return Char<1>(); }
  }
  //! Returns true if the instance …
Run Code Online (Sandbox Code Playgroud)

c++ template-meta-programming constexpr c++11

7
推荐指数
1
解决办法
442
查看次数

在C++中捕获lambdas的全局引用是否会抑制别名优化?

在为竞争条件工作时调试一些代码时出现了一个问题:这是一个简化示例:

//! Schedules a callable to be executed asynchronously
template<class F> void schedule(F &&f);

int main(void)
{
  bool flag(false);

  // Ignore the fact this is thread unsafe :)
  schedule([&] { flag=true; });

  // Can the compiler assume under strict aliasing that this check
  // for flag being false can be eliminated?
  if(!flag)
  {
    // do something
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

显然代码片段是线程不安全的 - bool标志需要是std :: atomic,然后seq_cst内存排序会强制编译器始终检查if测试的值.这个问题与此无关 - 它是关于初始化一个捕获全部引用lambda是否告诉编译器该标志可能已被别名,因此不能在稍后优化时检查标志值?

我自己的个人猜测是,构建一个[&flag] {...} lambda会暗示标志的潜在混叠,而[&] {...}使用潜在的别名来破坏所有自动初始化的变量听起来太极端反优化所以我猜不到.但是,如果引用捕获lambda不会对clobber进行任何别名,我也不会感到惊讶.

给你C++语言专家!我提前感谢你.

编辑:我知道缺乏线程安全将被视为一个答案,但这不是我要求的.让我进一步减少我的榜样:

int main(void)
{
  bool flag(false);

  // …
Run Code Online (Sandbox Code Playgroud)

c++ lambda strict-aliasing compiler-optimization c++11

5
推荐指数
1
解决办法
562
查看次数

如何检测某些可调用是否采用右值引用?

我一直试图写一个特征来判断一些可调用是否将右值引用作为其第一个参数.这使得一些元编程调整在调用可调用区域时是否使用移动或复制语义,其中可调用区域由外部代码提供(实际上一个是在用户提供的可调用类型上过载).

#include <functional>
#include <iostream>
#include <type_traits>

// Does the callable when called with Arg move?
template<class F, class Arg> struct is_callable_moving
{
  typedef typename std::decay<Arg>::type arg_type;
  typedef typename std::function<F(arg_type)>::argument_type parameter_type;
  static constexpr bool value = std::is_rvalue_reference<parameter_type>::value;
};

int main(void)
{
  auto normal = [](auto) {};    // Takes an unconstrained input.
  auto moving = [](auto&&) {};  // Takes a constrained to rvalue ref input.
  std::cout << "normal=" << is_callable_moving<decltype(normal), int>::value << std::endl;
  std::cout << "moving=" << is_callable_moving<decltype(moving), int>::value << std::endl; …
Run Code Online (Sandbox Code Playgroud)

c++ lambda template-meta-programming c++11 c++14

5
推荐指数
1
解决办法
386
查看次数

如何检测通用lambda在C++ 14中是否不可编译?

我有一个问题,检测通用lambda的实例化是否形成良好但不可编译,并检测它已经困扰我:

#include <functional>

class future
{
public:
  int get() & { return 5; }
};

// Gets the return type of F(A), returning a not_well_formed type if not well formed
template<class F, class A> struct get_return_type
{
  struct not_well_formed {};
  template<class _F, class _A> static not_well_formed test(...);
  template<class _F, class _A> static auto test(_F &&f) noexcept(noexcept(f(std::declval<_A>()))) -> decltype(f(std::declval<_A>()));
  using type = decltype(test<F, A>(std::declval<F>()));
  static constexpr bool is_noexcept = noexcept(test<F, A>(std::declval<F>()));
};

int main(void)
{
  auto foo=[](auto &&x) { return x.get(); …
Run Code Online (Sandbox Code Playgroud)

c++ lambda sfinae c++11 c++14

4
推荐指数
1
解决办法
393
查看次数

C++ 17模板推导指南不用于空参数集?

请考虑以下简化示例,也可以在https://godbolt.org/g/Et56cm查看:

#include <utility>

template <class T> struct success
{
  T value;
  constexpr success(T &&v)
      : value(std::move(v))
  {
  }
  constexpr success(const T &v)
      : value(v)
  {
  }
};
template <> struct success<void>
{
};
template <class T> success(T /*unused*/)->success<T>;
success()->success<void>;

int main(void)
{
    auto a = success{5};        // works
    auto b = success{};         // works
    auto c = success{"hello"};  // works
    auto d = success(5);        // works
    auto e = success();         // FAILS!
    auto f = success("hello");  // works …
Run Code Online (Sandbox Code Playgroud)

c++ templates template-argument-deduction c++17

3
推荐指数
1
解决办法
235
查看次数