实现B = f(A),已经定义了B和A数组以及B.

时间:2013-04-27 17:08:30

标签: c++ arrays function

假设我有一个数组B已经定义并在C ++代码中的某处使用过。现在,假设我有另一个已定义和初始化的数组A。我想创建一个转换f的函数A(例如,FFT),我希望转换的结果分配给B(当然,在转换之后) AB将更改其值)。我希望通过保持语法

来做到这一切
B=f(A);

即没有将B的地址作为参数传递给f。有可能:

  1. 没有临时的创作?
  2. 创建了临时工,但没有内存泄漏?
  3. 谢谢。

    编辑:以下答案中提供的解决方案摘要

    感谢RiaD,James Kanze,Shahbaz和Razispio的回答。

    我要求的是AB需要数组类的对象才能获得效率和效果。而且,在“标准”实现中,例如,具有配备有复制构造器的数组类,诸如B=f(A);的语法将需要创建临时。然而,应该提到临时性不一定是限制,因为许多编译器将能够忽略额外的临时工。与此相反,像f(A,B);这样的语法可以避免临时性。使用表达式模板的解决方案在内部使用B=f(A);时启用语法f(A,B);,使得临时使用可以忽略不计。一个有效的替代解决方案是使用移动赋值运算符,例如参见

    Move semantics and rvalue references in C++11

    有关详细信息,请参阅下面提供的答案。

4 个答案:

答案 0 :(得分:3)

使用std::vectorstd::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中,您可以提供移动构造函数和移动 赋值运算符,(可能)减少复制的机会 甚至更多。