我在许多地方读过,当make_shared<T>用于创建一个时shared_ptr<T>,它的控制块包含一个足够大的存储块来容纳一个T,然后该对象是在存储内部构建的,具有新的位置.像这样的东西:
template<typename T>
struct shared_ptr_control_block {
std::atomic<long> count;
std::atomic<long> weak_count;
std::aligned_storage_t<sizeof (T), alignof (T)> storage;
};
Run Code Online (Sandbox Code Playgroud)
但我有点困惑为什么我们不能只有一个成员变量与类型T?为什么要创建原始存储然后使用新的贴图?不能与普通的类型对象一步合并T吗?
对于这个结构:
struct Wrapper {
int value;
constexpr explicit Wrapper(int v) noexcept : value(v) {}
Wrapper(const Wrapper& that) noexcept : value(that.value) {}
};
Run Code Online (Sandbox Code Playgroud)
而这个功能:
constexpr Wrapper makeWrapper(int v)
{
return Wrapper(v);
}
Run Code Online (Sandbox Code Playgroud)
以下代码无法为Clang(Apple LLVM版本7.3.0)编译,但是对于GCC(4.9+)编译良好,两者都具有-Wall -Wextra -Werror -pedantic-errors:
constexpr auto x = makeWrapper(123);
Run Code Online (Sandbox Code Playgroud)
Clang抱怨说"非constexpr构造函数'Wrapper'不能用于常量表达式." 哪个编译器是对的?
如图所示这里,std::unique_ptr有两个constexpr构造空指针:
constexpr unique_ptr();
constexpr unique_ptr( nullptr_t );
Run Code Online (Sandbox Code Playgroud)
我对这两个构造函数有两个问题:
为什么我们需要两个?我们不能只声明一个:
constexpr unique_ptr( nullptr_t = nullptr );
Run Code Online (Sandbox Code Playgroud)是constexpr真的有用吗?我尝试在我的代码中执行此操作,但它没有编译(g ++ 6.1.0,-std=c++14):
constexpr std::unique_ptr<int> p;
// error: the type 'const std::unique_ptr<int>' of constexpr variable 'p'
// is not literal because 'std::unique_ptr<int>' has a non-trivial destructor
Run Code Online (Sandbox Code Playgroud)这是一个更多的设计问题(我知道为什么会发生这种情况,只是想看看人们如何处理它).假设我有一个简单的链表struct:
struct List {
int head;
std::shared_ptr<List> tail;
};
Run Code Online (Sandbox Code Playgroud)
在shared_ptr使多个列表之间的子列表的共享.但是,当列表变得很长时,可能会在其析构函数中发生堆栈溢出(由shared_ptrs 的递归释放引起).我尝试过使用显式堆栈,但由于尾部可以由多个列表拥有,因此非常棘手.如何设计我List以避免这个问题?
更新:澄清一下,我不是要重新发明轮子(std::forward_list).在List以上所述,仅为实际数据结构的简化版本.真正的数据结构是一个有向的非循环图,如果你想到它只是很多带有共享尾部/头部的链表.复制图表通常非常昂贵,因此数据共享是必要的.
更新2:我正在考虑显式遍历指针链并随时移动std::move.就像是:
~List()
{
auto p = std::move(tail);
while (p->tail != nullptr && p->tail.use_count() == 1) {
// Some other thread may start pointing to `p->tail`
// and increases its use count before the next line
p = std::move(p->tail);
}
}
Run Code Online (Sandbox Code Playgroud)
这似乎在单个线程中工作,但我担心线程安全.
这个帖子的接受答案通过价值与通过右值参考传递说明:
对于仅移动类型(as
std::unique_ptr),pass-by-value似乎是常态......
我对此有点怀疑.让我们说有一些不可复制的类型,Foo移动也不便宜; 和一些Bar有成员的类型Foo.
class Foo {
public:
Foo(const Foo&) = delete;
Foo(Foo&&) { /* quite some work */ }
...
};
class Bar {
public:
Bar(Foo f) : f_(std::move(f)) {} // (1)
Bar(Foo&& f) : f_(std::move(f)) {} // (2)
// Assuming only one of (1) and (2) exists at a time
private:
Foo f_;
};
Run Code Online (Sandbox Code Playgroud)
然后为以下代码:
Foo f;
...
Bar bar(std::move(f));
Run Code Online (Sandbox Code Playgroud)
构造函数(1)引发2个移动构造,而构造函数(2)只引发1.我还记得在Scott Meyers的Effective Modern C++中读到这个但是不能立即记住哪个项目.
所以我的问题是,对于仅移动类型(或者更一般地说,当我们想要转移参数的所有权时),我们是否应该更倾向于通过rvalue-reference来获得更好的性能?
更新: …
是否有可能阻止一组锁/期货/任何可阻止的实体,直到其中任何一个准备就绪?我们的想法是:
std::vector<std::future<T>> futures = ...;
auto ready_future = wait_until_an_element_is_ready(futures);
process(ready_future.get());
Run Code Online (Sandbox Code Playgroud)
我记得像libevent,libev和libuv这样的库具有IO任务的这种能力.但我不知道这些是否可以用于锁/期货.
我想到的一种方法就是让期货在完成后调用一个处理程序,但同时将处理程序比较并交换为null,这样其他期货就不能调用它.然而,这需要协调期货,因此无法对锁进行.
更新:似乎有一个针对C++ 2x 的提议.
C++核心指南提到了一个名为a的东西stack_array.它的用法如下:
const int n = 7;
int m = 9;
void f()
{
std::array<int, n> a1;
stack_array<int> a2(m); // A stack-allocated array.
// The number of elements are determined
// at construction and fixed thereafter.
// ...
}
Run Code Online (Sandbox Code Playgroud)
但是如何实施这样的课程呢?我们如何在运行时动态确定堆栈大小?
我正在尝试使用 CI 构建和测试我的 Rust 代码,我想知道cargo clippy(可能带有选项)是否涵盖了所有cargo check功能。我只需要运行cargo clippy,还是需要同时运行?
如本页http://en.cppreference.com/w/cpp/thread/async所示std::async,C++ 14中的一个签名已从C++ 11版本更改
template< class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
async( Function&& f, Args&&... args );
Run Code Online (Sandbox Code Playgroud)
至
template< class Function, class... Args>
std::future<std::result_of_t<std::decay_t<Function>(std::decay_t<Args>...)>>
async( Function&& f, Args&&... args );
Run Code Online (Sandbox Code Playgroud)
更改是在std::decay_t传递给函数和参数类型之前应用于函数和参数类型的s(将参考和cv限定符和衰减数组/函数移除到指针中)std::result_of.我不太明白为什么腐烂是有用的.例如,对于一个功能类型Fn(可能是封闭类的类型别名),传递Fn,Fn&&,const Fn&等等似乎都产生相同的结果.
有人能给我一个具体的例子,其中衰变是有用的吗?
更新:例如,这段代码:
#include <iostream>
#include <type_traits>
int main()
{
auto fn = [](auto x) -> int { return x + 1; };
using Fn = decltype(fn);
using FnRef = Fn&;
using FnCRef …Run Code Online (Sandbox Code Playgroud) 我一直在写这样的高阶函数:
template<typename F, typename... Args>
void doStuff(F f, Args&&... args)
{
// ...
f(std::forward<Args>(args)...);
// ...
}
Run Code Online (Sandbox Code Playgroud)
或者可以替换F f为F&& f.
但在我了解了ref-qualifiers(哎哟)之后,情况变得复杂了.想象一个仿函数类:
struct Foo {
void operator()(...) &;
void operator()(...) &&;
};
Run Code Online (Sandbox Code Playgroud)
然后我之前的实现doStuff将只调用该&方法,因为参数总是左值.
我认为解决这个问题的方法是这样实现doStuff:
template<typename F, typename... Args>
void doStuff(F&& f, Args&&... args)
{
// ...
std::forward<F>(f)(std::forward<Args>(args)...);
// ...
}
Run Code Online (Sandbox Code Playgroud)
这也是如何std::result_of在可能实现的.我想知道的是,这个实现有什么缺点,即我应该用它替换所有的HOF实现吗?