假设我有一个数组B
已经定义并在C ++代码中的某处使用过。现在,假设我有另一个已定义和初始化的数组A
。我想创建一个转换f
的函数A
(例如,FFT),我希望转换的结果分配给B
(当然,在转换之后) A
,B
将更改其值)。我希望通过保持语法
B=f(A);
即没有将B
的地址作为参数传递给f
。有可能:
谢谢。
编辑:以下答案中提供的解决方案摘要
感谢RiaD,James Kanze,Shahbaz和Razispio的回答。
我要求的是A
和B
需要数组类的对象才能获得效率和效果。而且,在“标准”实现中,例如,具有配备有复制构造器的数组类,诸如B=f(A);
的语法将需要创建临时。然而,应该提到临时性不一定是限制,因为许多编译器将能够忽略额外的临时工。与此相反,像f(A,B);
这样的语法可以避免临时性。使用表达式模板的解决方案在内部使用B=f(A);
时启用语法f(A,B);
,使得临时使用可以忽略不计。一个有效的替代解决方案是使用移动赋值运算符,例如参见
Move semantics and rvalue references in C++11
有关详细信息,请参阅下面提供的答案。
答案 0 :(得分:3)
使用std::vector
或std::array
示例:
vector<int> f(const vector<int>& a) {
return a;
}
b = f(a);
实际上,您不必使用其中一个类来存储,您可以使用自己的类operator =
YourClass& operator = (const vector<int>&/* there will be returned value of f, it may be std::array, std::vector or your own class.*/ v) {
//fill it here.
return *this;
}
您也可以为它提供移动构造函数,以避免不必要的复制。
例如
class Array {
int* data;
YourClass& operator = (YourClass&& v) {
swap(v.data, data);
}
}
YourClass f(const YourClass& a) {
//
}
Array a,b;
b = f(a);
答案 1 :(得分:1)
由于f
没有对B
的任何引用,因此它无法处理本地数组。因此,您必须将值复制到B
。所以在目前的形式中,没有办法。但是,如果你使f
内联,优化器可能只是帮助你 1 ,但这对于FFT来说不是一个好主意。
使用临时值但没有内存泄漏,您只需将数组包装在一个类中(或使用已经执行该操作的vector
)并返回该数组。请注意,非动态数组副本本身不会产生内存泄漏,在C ++中编写some_array = another_array
是不可能的。
如果您可以选择重新设计,最好的方法是致电f(A, B)
以获得最佳效果,
1 如果编译器足够智能,它会识别f
中的本地数组将被复制到B
,并且在内联版本中f
它可以使用B
本身,因为它可以访问它。
答案 2 :(得分:1)
如果您愿意为f(a)
使用自定义类型,则两者都可以(或非常接近b
)。这个想法是你已经有b
,因此你想在语义上将它作为参数传递给f
。例如,我们可以重载赋值运算符:
首先,定义一个表达式概念(这里表示为一个抽象类,但我们并不真的想使用虚拟调度)。这封装了一个计算,可以Evaluate
并在target
中返回结果。
template<typename T>
class Expression
{
public:
virtual void Evaluate(T& target) const = 0;
}
现在定义您的数组类,可以从Expression
类中分配。分配表达式后,将对其进行评估。
template<typename T>
class Array
{
T* ptr;
public:
template<typename Expression>
const Array<T> operator =(Expression const & expression)
{
expression.Evaluate(ptr);
}
}
现在,定义函数f
以返回表达式,在计算时,返回f(a)
。
class MyExpression
{
float* a;
public:
MyExpression(float* a) : a(a) {}
void Evaluate(float* target)
{
f(a, b);
}
}
MyExpression<float> f(float* a)
{
return MyExpression(a);
}
然后您可以按以下方式调用
Array b;
b = f(a);
这确实会创建一个临时的(在堆栈上),但它可以被内联。例如,假设我们有电话
b = f(a);
这相当于
b.operator = (f (a));
内联对operator =
的调用,我们得到
(f(a)).Evaluate(b);
现在,我们还可以内联f
,提供
(MyExpression(f)).Evaluate(b);
现在,编译器可以注意到这与执行
完全相同f(a, b);
直接做到这一点。因此,不需要创建临时MyExpression
,但首先它的成本可以忽略不计(它是sizeof(Array)
的堆栈分配)
请注意,矩阵库eigen使用此类策略来避免临时工具。
答案 3 :(得分:1)
首先,它取决于你对数组的意思。用通常的C ++
意义(std::vector
),永远不会有任何问题
内存泄漏;与通常的C含义(T[]
),B = f( A )
是
非法的。如果您定义自己的数组类型,那么它应该
在这方面,行为或多或少像std::vector
。
关于额外的临时性:f
应该采取其论点
作为const引用,这样就不会有复制传递
争论。至于返回值,正式有一个
复制,但允许编译器同时使用它,大多数情况下都可以
至少在某些时候。在赋值语句中,实际的
数组的数据可能会在赋值中复制
本身。
在C ++ 11中,您可以提供移动构造函数和移动 赋值运算符,(可能)减少复制的机会 甚至更多。