C++ 用于返回一组值的接口
我有一个函数,它接受一个数字并返回很多东西(比如int)。最干净的界面是什么?一些想法:C++ 用于返回一组值的接口,c++,c++11,c++98,C++,C++11,C++98,我有一个函数,它接受一个数字并返回很多东西(比如int)。最干净的界面是什么?一些想法: 返回一个向量。向量将被复制多次,这是低效的 返回一个向量*。我的getter现在必须分配向量本身以及元素。所有常见的问题都是谁必须释放向量,不能分配一次并使用同一个存储来多次调用getter,等等。这就是为什么STL算法通常避免分配内存,而希望传递内存 返回一个唯一的\u ptr。现在很清楚是谁删除了它,但我们还有其他问题 将向量作为参考参数。getter可以push_back(),调用者可以决定是否res
向量
。向量将被复制多次,这是低效的向量*
。我的getter现在必须分配向量本身以及元素。所有常见的问题都是谁必须释放向量,不能分配一次并使用同一个存储来多次调用getter,等等。这就是为什么STL算法通常避免分配内存,而希望传递内存唯一的\u ptr
。现在很清楚是谁删除了它,但我们还有其他问题向量
作为参考参数。getter可以push_back()
,调用者可以决定是否reserve()
空间。但是,如果传入的向量
为非空,getter应该怎么做?追加是否先清除它来覆盖?断言它是空的?如果函数的签名只允许一个解释就好了开始
和结束
迭代器。现在,我们需要返回实际写入的项目数(可能比期望的要少),调用方需要小心不要访问从未写入的项目迭代器
,调用者可以传递插入迭代器
char*
:)李>
return
vector
,它不会被复制,而是会被移动。在C++11中,标准容器支持移动语义,您应该使用选项1
它使函数的签名清晰,表明您只希望返回一个整数向量,这将是有效的,因为不会发出副本:将调用std::vector
的move构造函数(或者,很可能会应用命名返回值优化,导致不移动和不复制):
但是,即使在这种情况下,你也应该考虑这个惩罚对你的用例是否真的有意义。如果不是,您可能会选择更清晰的函数签名,但会牺牲一些CPU周期
此外,C++03编译器能够执行命名返回值优化,因此,尽管理论上应该根据返回的值构造临时副本,但实际上不可能发生复制。在C++11中,正确的答案是返回
std::vector
就是返回它,确保它将被显式或隐式移动。(更喜欢隐式移动,因为显式移动会阻止某些优化)
有趣的是,如果您担心重用缓冲区,最简单的方法是插入一个可选参数,该参数按如下值接受std::vector
:
std::vector<int> get_stuff( int how_many, std::vector<int> retval = std::vector<int>() ) {
// blah blah
return retval;
}
如果必须为每个隐藏的实现,则可能使用std::function
困难的方法是返回一个生成器或一对迭代器来生成所讨论的元素
当您一次只想处理一个元素,并且如果生成有问题的值很昂贵(可能需要遍历内存),这两种方法都可以避免无意义地分配缓冲区
在C++98中,我将使用一个向量&
和clear()
它。你自己写的:
…这就是为什么STL算法通常避免分配内存,而希望传递内存的原因
除了STL算法通常不“希望传递内存”,它们在迭代器上运行。这是为了将算法与容器解耦,从而产生:
备选案文8
通过返回输入迭代器,将值生成与这些值的使用和存储分离
最简单的方法是使用,但下面是一个草图机制(主要是因为我打字比思考快)
输入迭代器类型
(使用C++11,但可以用函数指针替换std::function
,也可以硬编码生成逻辑):
#包括
#包括
模板
类生成器:公共std::迭代器{
整数计数;
std::函数生成;
公众:
生成器():计数(0){}
生成器(int count,std::function func):计数(count)
,生成{(func){}
发电机(发电机常数和其他):计数(其他.计数)
,生成{(其他.生成{}
//为简洁起见,省略了移动、赋值等
T运算符*(){return generate_u();}
生成器和运算符++(){
--伯爵;
归还*这个;
}
生成器运算符++(int){
发电机tmp(*此);
++*这,;
返回tmp;
}
布尔运算符==(生成器常量和其他)常量{
返回计数=other.count;
}
布尔运算符!=(发电机常数和其他)常数{
返回!(*此==其他);
}
};
示例生成器函数
(同样,对于C++98来说,用一个离线函数替换lambda是很简单的,但这是较少的类型)
#包括
生成器开始随机整数(int n){
静态标准:minstd_rand prng;
静态标准::统一分布pdf;
发电机rv(n,
[](){返回pdf(prng);}
);
返回rv;
}
生成器结束\u随机\u整数(){
返回生成器();
}
示例使用
#包括
#包括
#包括
int main()
{
使用名称空间std;
矢量输出;
你能用C++11编译器吗?是的,我用的是C++11,但我也很好奇如何在C++98中实现。在C++11中,向量是最好的,因为它不会被复制多次。在这两种情况下,向量的设计仍然很差,除非有充分的理由,否则它不能被复制
void foo(std::vector<int>& v)
{
// Fill in v...
}
std::vector<int> get_stuff( int how_many, std::vector<int> retval = std::vector<int>() ) {
// blah blah
return retval;
}
#include <iostream>
struct Foo {
int get_element(int i) const { return i*2+1; }
template<typename Lambda>
void for_each_element( int up_to, Lambda&& f ) {
for (int i = 0; i < up_to; ++i ) {
f( get_element(i) );
}
}
};
int main() {
Foo foo;
foo.for_each_element( 7, [&](int e){
std::cout << e << "\n";
});
}
#include <functional>
#include <iterator>
template <typename T>
class Generator: public std::iterator<std::input_iterator_tag, T> {
int count_;
std::function<T()> generate_;
public:
Generator() : count_(0) {}
Generator(int count, std::function<T()> func) : count_(count)
, generate_(func) {}
Generator(Generator const &other) : count_(other.count_)
, generate_(other.generate_) {}
// move, assignment etc. etc. omitted for brevity
T operator*() { return generate_(); }
Generator<T>& operator++() {
--count_;
return *this;
}
Generator<T> operator++(int) {
Generator<T> tmp(*this);
++*this;
return tmp;
}
bool operator==(Generator<T> const &other) const {
return count_ == other.count_;
}
bool operator!=(Generator<T> const &other) const {
return !(*this == other);
}
};
#include <random>
Generator<int> begin_random_integers(int n) {
static std::minstd_rand prng;
static std::uniform_int_distribution<int> pdf;
Generator<int> rv(n,
[]() { return pdf(prng); }
);
return rv;
}
Generator<int> end_random_integers() {
return Generator<int>();
}
#include <vector>
#include <algorithm>
#include <iostream>
int main()
{
using namespace std;
vector<int> out;
cout << "copy 5 random ints into a vector\n";
copy(begin_random_integers(5), end_random_integers(),
back_inserter(out));
copy(out.begin(), out.end(),
ostream_iterator<int>(cout, ", "));
cout << "\n" "print 2 random ints straight from generator\n";
copy(begin_random_integers(2), end_random_integers(),
ostream_iterator<int>(cout, ", "));
cout << "\n" "reuse vector storage for 3 new ints\n";
out.clear();
copy(begin_random_integers(3), end_random_integers(),
back_inserter(out));
copy(out.begin(), out.end(),
ostream_iterator<int>(cout, ", "));
}