从功能返回容器:优化速度和现代风格
Returning container from function: optimizing speed and modern style
不完全是一个问题,虽然只是一些我一直在思考的东西,如何编写这样的代码更优雅的风格,同时充分利用新的c++标准等。下面是示例
将斐波那契数列返回到最多N个值的容器中(对于那些不擅长数学的人来说,这只是将前两个值与前两个值相加等于1。(1,1,2,3,5,8,13,…)
示例:
std::vector<double> vec;
running_fibonacci_seq(vec,30000000);
1)
template <typename T, typename INT_TYPE>
void running_fibonacci_seq(T& coll, const INT_TYPE& N)
{
coll.resize(N);
coll[0] = 1;
if (N>1) {
coll[1] = 1;
for (auto pos = coll.begin()+2;
pos != coll.end();
++pos)
{
*pos = *(pos-1) + *(pos-2);
}
}
}
2)相同,但使用rvalue &&而不是&1. e。
void running_fibonacci_seq(T&& coll, const INT_TYPE& N)
编辑:正如下面评论的用户所注意到的,右值和左值对计时没有影响——速度实际上是相同的,原因在评论
中讨论过N = 30,000,000
的结果Time taken for &:919.053ms
Time taken for &&: 800.046ms
首先,我知道这真的不是一个问题,但这些或哪个是最好的现代c++代码?使用右值引用(&&),似乎移动语义已经就绪,并且没有进行不必要的复制,这在时间上有了小小的改进(由于未来的实时应用程序开发,对我来说很重要)。一些具体的"问题"
a)传递一个容器(在我的例子中是vector)给函数作为参数并不是一个优雅的解决方案,如何真正使用右值。这是真的吗?如果是这样,那么在上面的例子中,右值如何真正显示它的轻?
b) col .resize(N);调用和N=1的情况下,是否有一种方法可以避免这些调用,从而使用户只使用函数而不动态创建vector的大小。模板元编程可以在这里使用,所以向量在编译时分配一个特定的大小?(即running_fibonacci_seq<30000000>),因为数字可能很大,是否有必要使用模板元编程,如果是这样,我们可以使用这个(链接)也
c)有没有更优雅的方法?我有一种感觉std::transform函数可以使用lambdas例如
void running_fibonacci_seq(T&& coll, const INT_TYPE& N)
{
coll.resize(N);
coll[0] = 1;
coll[1] = 1;
std::transform (coll.begin()+2,
coll.end(), // source
coll.begin(), // destination
[????](????) { // lambda as function object
return ????????;
});
}
[1] http://cpptruths.blogspot.co.uk/2011/07/want-speed-use-constexpr-meta.html
由于"引用塌陷",这段代码没有使用右值引用,也没有移动任何东西:
template <typename T, typename INT_TYPE>
void running_fibonacci_seq(T&& coll, const INT_TYPE& N);
running_fibonacci_seq(vec,30000000);
当你意识到这一点时,你所有的问题(和现有的评论)都变得毫无意义。
显而易见的答案:
std::vector<double> running_fibonacci_seq(uint32_t N);
为什么?
因为const-ness:
std::vector<double> const result = running_fibonacci_seq(....);
因为更简单的不变量:
void running_fibonacci_seq(std::vector<double>& t, uint32_t N) {
// Oh, forgot to clear "t"!
t.push_back(1);
...
}
速度呢?
有一种称为返回值优化的优化,它允许编译器在许多情况下省略副本(并直接在调用者的变量中构建结果)。c++标准特别允许,即使复制/移动构造函数有副作用。
那么,为什么要传递"out"参数呢?
- 你只能有一个返回值(叹号)
- 您可能希望重用分配的资源(这里是
t
的内存缓冲区)
Profile this:
#include <vector>
#include <cstddef>
#include <type_traits>
template <typename Container>
Container generate_fibbonacci_sequence(std::size_t N)
{
Container coll;
coll.resize(N);
coll[0] = 1;
if (N>1) {
coll[1] = 1;
for (auto pos = coll.begin()+2;
pos != coll.end();
++pos)
{
*pos = *(pos-1) + *(pos-2);
}
}
return coll;
}
struct fibbo_maker {
std::size_t N;
fibbo_maker(std::size_t n):N(n) {}
template<typename Container>
operator Container() const {
typedef typename std::remove_reference<Container>::type NRContainer;
typedef typename std::decay<NRContainer>::type VContainer;
return generate_fibbonacci_sequence<VContainer>(N);
}
};
fibbo_maker make_fibbonacci_sequence( std::size_t N ) {
return fibbo_maker(N);
}
int main() {
std::vector<double> tmp = make_fibbonacci_sequence(30000000);
}
fibbo_maker
的东西只是我聪明。但它可以让我推断出你想要的fibbo序列类型,而不必重复它。
- Qt VTK交互风格的信号到小部件
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 为什么在读取文件大小时文件IO速度会发生变化
- Visual Studio 2019:插入多个C++风格的单行注释
- 如何在本地机器上运行c++和javascript客户端代码(hackerbank风格)
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- 文件系统:复制功能的速度秘诀是什么
- 学习多线程C++:添加线程不会使执行速度更快,即使它看起来应该
- 在C++中使用并行化的预期速度是多少(不是 OpenMp,而是 <thread>)
- 两个连续的 OpenMP 并行区域会相互减慢速度
- 查找标准::hash_map与标准::矢量的速度
- 重载运算符<<采用谷歌 C++ 风格
- 加快在C++中读取/处理日志文件的速度
- C++许多 SFINAE 风格的过载
- 为什么这些算法的运行速度比它们应该的要快?
- 如何提高文件的读取速度?
- 通过libpqxx提高PostgreSQL数据库的更新速度
- 使用 IMFSinkWriter 编码的视频的播放速度会根据宽度而变化
- 计算车辆之间的距离并设置速度,使距离保持不变,例如 5 米
- 从功能返回容器:优化速度和现代风格