我一直在使用pimpl成语制作一些对象,但我不确定是否使用std::shared_ptr
或std::unique_ptr
.
据我所知,std::unique_ptr
是更有效的,但是这是没有这么多的问题,对我来说,因为这些物体是比较重量级反正做的成本std::shared_ptr
比std::unique_ptr
相对较小.
我目前std::shared_ptr
只是因为额外的灵活性.例如,使用a std::shared_ptr
允许我将这些对象存储在散列映射中以便快速访问,同时仍然能够将这些对象的副本返回给调用者(因为我相信任何迭代器或引用可能很快变得无效).
但是,这些对象确实没有被复制,因为更改会影响所有副本,所以我想知道也许使用std::shared_ptr
和允许副本是某种反模式或坏事.
它是否正确?
我最近发现自己在C++ 11模式下使用gcc 4.5的以下宏:
#define RETURN(x) -> decltype(x) { return x; }
Run Code Online (Sandbox Code Playgroud)
并编写如下函数:
template <class T>
auto f(T&& x) RETURN (( g(h(std::forward<T>(x))) ))
Run Code Online (Sandbox Code Playgroud)
我一直这样做是为了避免不得不有效地编写函数体两次,并保持身体和返回类型的同步(这在我看来是等待发生的灾难)的不便.
问题是这种技术只适用于一行功能.所以当我有这样的事情时(复杂的例子):
template <class T>
auto f(T&& x) -> ...
{
auto y1 = f(x);
auto y2 = h(y1, g1(x));
auto y3 = h(y1, g2(x));
if (y1) { ++y3; }
return h2(y2, y3);
}
Run Code Online (Sandbox Code Playgroud)
然后我必须在返回类型中添加一些可怕的东西.
此外,每当我更新函数时,我都需要更改返回类型,如果我没有正确更改它,如果我很幸运,我会收到编译错误,或者更坏的情况下会出现运行时错误.必须将更改复制并粘贴到两个位置并保持同步,我觉得这不是一个好习惯.
而且我想不出一种情况,我希望在返回时使用隐式强制转换而不是显式强制转换.
当然有一种方法可以要求编译器推断出这些信息.编译器保守秘密有什么意义?我认为C++ 11的设计不需要这样的复制.
我最近问了很多关于的问题TVar
,我仍然对活锁感到担忧.
所以我想到了这个结构:
TVar
).然而,B保持其当前重试的优先级. 我相信这个系统可以防止死锁,但也可以防止饥饿(不像TVar
).我想知道是否有人实施了这样的系统,因为它看起来相当明显,我不想重新发明轮子.
当然,可以容易地扩展这种方法以允许用户指定优先级.
优先级可能是一对(user_supplied_prio, auto_increment)
,与user_supplied_prio
采取优先次序,但相同优先级的任务以FIFO的顺序解决.
评论/解决方案:
实际上,当我想到它时,我所描述的已经存在于Haskell中,只需使用一个IORef
包裹所有数据,并且仅使用atomicModifyIORef
.这atomicModifyIORef
将确保按顺序应用交易.但是,有人可能认为这意味着数据结构是顺序的(即有效地限于一个线程),但由于懒惰,它实际上是并行的.
要解释这一点,请考虑一个昂贵的功能f
.我们将Data.Map
使用键"foo" 将其应用于数据.
这取代(foo -> x)
了(foo -> future(f x))
.这个帖子应该继续解决(f x)
实际问题,但在此期间我们可以将g应用于"bar".由于将g应用于"bar"不需要"foo"的结果,我们可以同时解决这个问题.
没有死锁,没有饥饿,最终将处理所有交易(大致按照收到的顺序).
我正在阅读ClassyPrelude的公告,并且到了这里:
instance (b ~ c, CanFilterFunc b a) => CanFilter (b -> c) a where
filter = filterFunc
Run Code Online (Sandbox Code Playgroud)
作者随后提到这不起作用:
instance (CanFilterFunc b a) => CanFilter (c -> c) a where
filter = filterFunc
Run Code Online (Sandbox Code Playgroud)
这对我来说很有意义,因为c
它与左边的约束完全无关.
但是,文章中没有提到的内容和我不理解的是为什么这不起作用:
instance (CanFilterFunc b a) => CanFilter (b -> b) a where
filter = filterFunc
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么这与第一个提到的定义不同?也许GHC类型推断的一个有效例子会有所帮助吗?
可以说我们有以下代码:
std::vector<int> f()
{
std::vector<int> y;
...
return y;
}
std::vector<int> x = ...
x = f();
Run Code Online (Sandbox Code Playgroud)
看来编译器有两种方法:
(a)NRVO:Destruct x,然后构造f()代替x.
(b)移动:在temp空间中构造f(),将f()移动到x,destruct f().
根据标准,编译器是否可以自由使用这两种方法?
c++ optimization move-semantics return-value-optimization c++11
请考虑以下代码:
#include <iostream>
#include <type_traits>
struct A
{
A() {}
A(const A&) { std::cout << "Copy" << std::endl; }
A(A&&) { std::cout << "Move" << std::endl; }
};
template <class T>
struct B
{
T x;
};
#define MAKE_B(x) B<decltype(x)>{ x }
template <class T>
B<T> make_b(T&& x)
{
return B<T> { std::forward<T>(x) };
}
int main()
{
std::cout << "Macro make b" << std::endl;
auto b1 = MAKE_B( A() );
std::cout << "Non-macro make b" << std::endl;
auto b2 …
Run Code Online (Sandbox Code Playgroud) 我想知道我的构造者最好的形式.以下是一些示例代码:
class Y { ... }
class X
{
public:
X(const Y& y) : m_y(y) {} // (a)
X(Y y) : m_y(y) {} // (b)
X(Y&& y) : m_y(std::forward<Y>(y)) {} // (c)
Y m_y;
}
Y f() { return ... }
int main()
{
Y y = f();
X x1(y); // (1)
X x2(f()); // (2)
}
Run Code Online (Sandbox Code Playgroud)
据我所知,这是编译器在每种情况下都能做到的最好的.
(1a)y被复制到x1.m_y(1份)
(1b)将y复制到X的构造函数的参数中,然后复制到x1.m_y(2个副本)
(1c)y移入x1.m_y(1移动)
(2a)将f()的结果复制到x2.m_y(1份)
(2b)将f()构造成构造函数的参数,然后复制到x2.m_y(1个副本)
(2c)在堆栈上创建f(),然后移入x2.m_y(1 move)
现在几个问题:
在这两个方面,传递const引用并不差,有时候比传递值更好.这似乎违背了"想要速度?通过价值"的讨论..对于C++(不是C++ 0x),我应该坚持使用const引用作为这些构造函数,还是应该通过值传递?对于C++ 0x,我应该通过rvalue引用传递值吗?
对于(2),如果临时直接构造成x.m_y,我更喜欢.我认为即使是rvalue版本也需要一个移动,除非对象分配动态内存,否则移动与复制一样多.有没有办法对此进行编码,以便允许编译器避免这些副本和移动?
我已经在我认为编译器可以做得最好的事情和我自己的问题中做了很多假设.如果不正确,请更正其中任何一项.
如该代码所示这里,从make_shared返回的对象的大小是两个指针.
但是,为什么不能make_shared
像下面这样工作(假设T是我们正在制作共享指针的类型):
结果
make_shared
是一个指针大小,它指向已分配的大小内存sizeof(int) + sizeof(T)
,其中int是引用计数,并且这在指针的构造/销毁时递增和递减.
unique_ptr
s只是一个指针的大小,所以我不确定为什么共享指针需要两个.据我所知,它需要一个引用计数,它make_shared
可以与对象本身一起放置.
此外,是否有任何实现以我建议的方式实现(不必intrusive_ptr
为特定对象使用s)?如果没有,我建议实施的原因是什么原因可以避免?
有人可以解释一下atomicModifyIORef
有效吗?特别是:
(1)是否等待锁定,或者乐观地尝试重试(如果存在争用TVar
).
(2)为什么签名atomicModifyIORef
不同于签名modifyIORef
?特别是,这个额外的变量是什么b
?
编辑:我想我已经找到了(2)的答案,因为这b
是一个要提取的值(如果不需要,这可以是空的).在单线程程序中,知道该值是微不足道的,但在多线程程序中,人们可能想知道在应用函数时先前的值是什么.我假设这就是为什么modifyIORef
没有这个额外的返回值(因为这样的modifyIORef
返回值的使用可能应该使用atomicModifyIORef
.我仍然对(1)的答案感兴趣.
我正在尝试生成代码(目前使用clang ++ - 3.8),它添加了两个由多个机器字组成的数字.为了简化目前我只添加128位数字,但我希望能够概括这一点.
首先是一些typedef:
typedef unsigned long long unsigned_word;
typedef __uint128_t unsigned_128;
Run Code Online (Sandbox Code Playgroud)
而"结果"类型:
struct Result
{
unsigned_word lo;
unsigned_word hi;
};
Run Code Online (Sandbox Code Playgroud)
第一个函数f
采用两对无符号字并返回结果,作为一个中间步骤,在添加它们之前将这两个64位字放入一个128位字中,如下所示:
Result f (unsigned_word lo1, unsigned_word hi1, unsigned_word lo2, unsigned_word hi2)
{
Result x;
unsigned_128 n1 = lo1 + (static_cast<unsigned_128>(hi1) << 64);
unsigned_128 n2 = lo2 + (static_cast<unsigned_128>(hi2) << 64);
unsigned_128 r1 = n1 + n2;
x.lo = r1 & ((static_cast<unsigned_128>(1) << 64) - 1);
x.hi = r1 >> 64;
return x;
}
Run Code Online (Sandbox Code Playgroud)
这实际上非常好地内联:
movq 8(%rsp), …
Run Code Online (Sandbox Code Playgroud) c++ ×7
c++11 ×5
haskell ×3
optimization ×3
concurrency ×2
shared-ptr ×2
adx ×1
assembly ×1
atomicity ×1
clang ×1
constructor ×1
deadlock ×1
locking ×1
macros ×1
pimpl-idiom ×1
return-value ×1
rvalue ×1
stm ×1
unique-ptr ×1