- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
funObj
)。 funObj
类的定义中,定义了一个称为id
的积分成员变量以保存所构造的每个funObj
的ID,并定义了一个静态积分成员变量n
来计数创建的funObj
对象。 funObj
时,n
都会增加1,并将其值分配给新创建的id
的funObj
字段。 stdout
上,以表示它们的调用以及它们所引用的funObj
的ID。 func
函数,该函数将funObj
类型的值对象作为输入。 #include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
template<typename T>
class funObj {
std::size_t id;
static std::size_t n;
public:
funObj() : id(++n)
{
std::cout << " Constructed via the default constructor, object foo with ID(" << id << ")" << std::endl;
}
funObj(funObj const &other) : id(++n)
{
std::cout << " Constructed via the copy constructor, object foo with ID(" << id << ")" << std::endl;
}
~funObj()
{
std::cout << " Destroyed object foo with ID(" << id << ")" << std::endl;
}
void operator()(T &elem)
{
}
T operator()()
{
return 1;
}
};
template<typename T>
void func(funObj<T> obj) { obj(); }
template<typename T>
std::size_t funObj<T>::n = 0;
int main()
{
std::vector<int> v{ 1, 2, 3, 4, 5, };
std::cout << "> Calling `func`..." << std::endl;
func(funObj<int>());
std::cout << "> Calling `for_each`..." << std::endl;
std::for_each(std::begin(v), std::end(v), funObj<int>());
std::cout << "> Calling `generate`..." << std::endl;
std::generate(std::begin(v), std::end(v), funObj<int>());
// std::ref
std::cout << "> Using `std::ref`..." << std::endl;
auto fobj1 = funObj<int>();
std::cout << "> Calling `for_each` with `ref`..." << std::endl;
std::for_each(std::begin(v), std::end(v), std::ref(fobj1));
std::cout << "> Calling `generate` with `ref`..." << std::endl;
std::for_each(std::begin(v), std::end(v), std::ref(fobj1));
return 0;
}
Calling
func
...Constructed via the default constructor, object foo with ID(1)
Destroyed object foo with ID(1)
调用for_each
...
Constructed via the default constructor, object foo with ID(2)
Constructed via the copy constructor, object foo with ID(3)
Destroyed object foo with ID(2)
Destroyed object foo with ID(3)
调用generate
...
Constructed via the default constructor, object foo with ID(4)
Constructed via the copy constructor, object foo with ID(5)
Destroyed object foo with ID(5)
Destroyed object foo with ID(4)
使用std::ref
...
Constructed via the default constructor, object foo with ID(6)
用for_each
调用ref
...
用generate
调用ref
...
Destroyed object foo with ID(6)
讨论:
从上面的输出中可以看到,使用func
类型的临时对象调用函数funObj
会导致构造单个funObj
对象(即使func
通过值传递其参数)。但是,当将funObj
类型的临时对象传递给STL算法std::for_each
和std::generate
时,情况似乎并非如此。在前一种情况下,将引发复制构造函数并构造一个额外的funObj
。在许多应用中,创建这种“不必要的”拷贝会大大降低算法的性能。基于这一事实,提出了以下问题。
问题:
我知道大多数STL算法都按值传递其参数。但是,与 func
(也按值传递其输入参数)相比,STL算法会生成一个额外的拷贝。此“不必要”拷贝的原因是什么?是否有消除这种“不必要”拷贝的方法? 在每种情况下分别调用 std::for_each(std::begin(v), std::end(v), funObj<int>())
和func(funObj<int>())
时,临时对象funObj<int>
驻留在哪个范围内?我尝试使用 std::ref
来强制通过引用传递,并且如您所见,消除了“不必要的”拷贝。但是,当我尝试将临时对象传递给std::ref
(即std::ref(funObj<int>())
)时,出现编译器错误。为什么这种陈述是非法的?使用VC++ 2013生成了输出。如您所见,调用 std::for_each
时存在异常,以相反的顺序调用对象的析构函数。为什么会这样?当我在运行GCC v4.8的Coliru上运行代码时,析构函数异常已修复,但是 std::generate
不会生成额外的拷贝。为什么会这样?
详细信息/评论:
上面的输出是从VC++ 2013生成的。
更新:
我还向 funObj
类添加了一个move构造函数(请参见下面的代码)。
funObj(funObj&& other) : id(other.id)
{
other.id = 0;
std::cout << " Constructed via the move constructor, object foo with ID(" << id << ")" << std::endl;
}
我还已在VC++ 2013中启用了完全优化并在 Release模式下进行了编译。
输出(VC++ 2013):
Calling
func
...Constructed via the default constructor, object foo with ID(1)
Destroyed object foo with ID(1)
调用for_each
...
Constructed via the default constructor, object foo with ID(2)
Constructed via the move constructor, object foo with ID(2)
Destroyed object foo with ID(2)
Destroyed object foo with ID(0)
调用generate
...
Constructed via the default constructor, object foo with ID(3)
Constructed via the copy constructor, object foo with ID(4)
Destroyed object foo with ID(4)
Destroyed object foo with ID(3)
使用std::ref
...
Constructed via the default constructor, object foo with ID(5)
用for_each
调用ref
...
用generate
调用ref
...
Destroyed object foo with ID(5)
输出GCC 4.8
Calling
func
...Constructed via the default constructor, object foo with ID(1)
Destroyed object foo with ID(1)
调用for_each
...
Constructed via the default constructor, object foo with ID(2)
Constructed via the move constructor, object foo with ID(2)
Destroyed object foo with ID(2)
Destroyed object foo with ID(0)
调用generate
...
Constructed via the default constructor, object foo with ID(3)
Destroyed object foo with ID(3)
Constructed via the default constructor, object foo with ID(4)
用for_each
调用ref
...
用generate
调用ref
...
Destroyed object foo with ID(4)
似乎VC++ 2013std::generate
如果启用了优化标志且编译处于 Release模式,并且定义了move构造函数,则将生成一个额外的拷贝。
最佳答案
1 - I know that most STL algorithms pass their argument by value. However, compared to func, that also passes its input argument by value, the STL algorithms generate an extra copy. What's the reason for this "unnecessary" copy?
func
返回void,因此少了一个拷贝。
generate
不返回任何东西(请参阅dyp)的评论2 - Is there a way to eliminate such "unnecessary" copies?
std::ref
的拷贝(不过您的对象将不会被复制)
auto fobj1 = funObj<int>();
std::for_each<std::vector<int>::iterator, std::vector<int>::iterator,
funObj<int>&> // this is where the magic happens !!
(std::begin(v), std::end(v), fobj1);
3 - When calling std::for_each(std::begin(v), std::end(v), funObj()) and func(funObj()) in which scope does temporary object funObj lives, for each case respectively?
std_for_each
的主体扩展如下:
template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function fn)
{ // 1
while (first!=last) {
fn (*first);
++first;
}
return fn; // or, since C++11: return move(fn);
// 2
}
template<typename T>
void func(funObj<T> obj)
{ // 1.
obj();
// 2.
}
1
和
2
标记生命周期。请注意,虽然
如果返回值优化应用了(已命名或未命名),则编译器可能会生成将返回值(函数对象位于for_each中)放置在调用方的堆栈框架中的代码,因此使用生命周期更长。
4 - I've tried to use std::ref in order to force pass-by-reference and as you can see the "unnecessary" copy was eliminated. However, when I try to pass a temporary object to std::ref (i.e., std::ref(funObj())) I get a compiler error. Why such kind of statements are illegal?
std::ref
不适用于r值引用(后接STL代码):
template<class _Ty>
void ref(const _Ty&&) = delete;
5 - The output was generated using VC++2013. As you can see there's an anomaly when calling std::for_each the destructors of the objects are being called in reversed order. Why is that so?
6 - When I run the code on Coliru that runs GCC v4.8 the anomaly with destructors is fixed however std::generate doesn't generate an extra copy. Why is that so?
for_each
中的仿函数和generate
中的生成器均按值传递(,没有签名接受r值引用),因此显然,这是复制的问题elision 保存多余的拷贝。 template<typename _InputIterator, typename _Function>
_Function
for_each(_InputIterator __first, _InputIterator __last, _Function __f)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_requires_valid_range(__first, __last);
for (; __first != __last; ++__first)
__f(*__first);
return _GLIBCXX_MOVE(__f);
}
关于c++ - 调用C++/STL算法时消除不必要的拷贝,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23613574/
jQuery attributeContainsPrefix [name^="value"] 对比 attributeStartsWith [name|="value"] 实际区别是什么? 最佳答案
在1.1部分在RFC 6749中,有四种角色:资源拥有者、资源服务器、客户端和授权服务器。 如果客户端和资源所有者是同一实体,OAuth 是否变得多余或不必要? 例如,我有一个封闭的 API 和一个面
我有一段代码,其中有一个带有保护子句的 raise 语句: def validate_index index # Change to SizeError raise ArgumentError
我看到了这篇文章( JPA Entity Lifecycle Events vs database trigger ),但它并没有像我在这里那样明确地询问: 当我插入 PK 值为 (null) 的行时
所以,我有一段代码看起来像 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){ // Do something }
我是一名优秀的程序员,十分优秀!