簡體   English   中英

從具有'void'返回類型的函數中獲取結果,而結果變量是輸入參數之一-C ++

[英]Getting results from functions with 'void' return type, while resulting variable is one of the input arguments - C++

我得到了這個數學例程庫(沒有文檔),可以在大學里完成某些任務。 我所遇到的問題是,盡管這些函數相互調用或是另一個函數的一部分,但所有函數都具有void返回類型,因此需要它們的計算結果。

這是從庫中提取的一段(簡化的)代碼。 不要理會代碼中的數學,這並不重要。 僅僅傳遞參數並返回結果令我感到困惑(如代碼后所述):

// first function

void vector_math // get the (output) vector we need
 ( 
   double inputV[3], // input vector
   double outputV[3] // output vector
 )
 {
      // some variable declarations and simple arithmetics
      // .....
      //

      transposeM(matrix1, matrix2, 3, 3 ); // matrix2 is the result

      matrixXvector( matrix2, inputV, outputV) // here you get the result, outputV
 }

////////

// second function

 void transposeM // transposes a matrix 
    ( 
      std::vector< std::vector<double> > mat1, // input matrix
      std::vector< std::vector<double> > &mat2, // transposed matrix
      int mat1rows, int mat1columns 
    )
   {         
   int row,col;

    mat2.resize(mat1columns);  // rows
     for (std::vector< std::vector<double> >::iterator it=mat2.begin(); it !=mat2.end();++it)
          it->resize(mat1rows);

 for (row = 0; row < mat1rows; row++)
     {
     for (col = 0; col < mat1columns; col++)
         mat2[col][row] = mat1[row][col];
     }
   }

   ////////

   // third function

   void matrixXvector // multiply matrix and vector
    (
          std::vector< std::vector<double> > inMatrix,
          double inVect[3],
          double outVect[3]
    )
      {
     int row,col,ktr;

     for (row = 0; row <= 2; row++)
      {
     outVect[row]= 0.0;
     for (ktr = 0; ktr <= 2; ktr++)
         outVect[row]= outVect[row] + inMatrix[row][ktr] * inVect[ktr];
       }
   }

因此,主程序正在調用“ vector_math”。 它以inputV作為輸入,結果應為outputV。 但是,outputV是輸入參數之一,並且該函數返回void。 稍后在調用“ transposeM”和“ matrixXvector”時也會發生類似的過程。

為什么輸出變量是輸入參數之一? 結果如何返回並用於進一步的計算? 這種傳遞和返回參數如何工作?

因為我是一個初學者,並且也從未見過這種編碼風格,所以我不理解傳遞參數(尤其是給出輸出)在這些函數中的工作方式。 因此,我不知道如何使用它們以及對它們有什么期望(它們將實際做什么)。 因此,我非常感謝您做出這樣的解釋,使我對這些過程更加清楚。

額外:

謝謝大家的好評。 這是我第一次幾乎無法決定接受哪個答案,即使我這樣做對其他人也不公平。 但是,如果有人願意回答(因為評論就足夠了),我想添加一個額外的問題。 這種編碼輸入/輸出自變量的“舊式”樣式是否具有其名稱或引用它的任何其他表達式?

這是一種返回某些或多個值的“舊”(但仍然很流行)樣式。 它是這樣的:

void copy (const std::vector<double>& input, std::vector<double>& output) {
    output = input;
}

int main () {
    std::vector<double> old_vector {1,2,3,4,5}, new_vector;
    copy (old_vector, new_vector); // new_vector now copy of old_vector
}

因此,基本上,您可以給函數一個或多個輸出參數以寫入其計算結果。

如果通過值或const引用傳遞輸入參數(即,您不打算更改它們),盡管按值傳遞只讀參數可能在性能上代價高昂,但這並不重要。 在第一種情況下,您將復制輸入對象並在函數中使用副本,在后一種情況中,只需讓函數看到原始對象並防止使用const對其進行修改。 輸入參數的const是可選的,但將其保留為const可以使函數更改其值(可能不是您想要的值),並禁止將臨時變量作為輸入傳遞。

輸入參數必須由非常量引用傳遞,以允許函數對其進行更改。

另一個甚至更老的“ C-isher”風格是傳遞輸出指針或原始數組,就像您的第一個函數一樣。 這有潛在的危險,因為指針可能未指向有效的內存,但仍散布得很廣。 它的工作原理基本上與第一個示例相同:

// Copies in to int pointed to by out
void copy (int in, int* out) {
    *out = in;
}

// Copies int pointed to by in to int pointed to by out
void copy (const int* in, int* out) {
    *out = *in;
}

// Copies length ints beginning from in to length ints beginning at out
void copy (const int* in, int* out, std::size_t length) {
    // For loop for beginner, use std::copy IRL:
    // std::copy(in, in + length, out);
    for (std::size_t i = 0; i < length; ++i)
        out[i] = in[i];
}

第一個示例中的數組基本上像指針一樣工作。

鮑姆的答案是准確的,但可能不像C / C ++初學者所希望的那樣詳盡。

進入函數的實際參數值始終按值(即位模式)傳遞,並且不能以調用者可讀的方式進行更改。 但是-這是關鍵-參數中的那些位實際上可能是指針(或引用),它們不直接包含數據,而是在內存中包含包含實際值的位置。

示例:在這樣的函數中:

void foo(double x, double output) { output = x ^ 2; }

將輸出變量命名為“輸出不會改變任何內容-調用者無法獲得結果。

但是像這樣:

void foo(double x, double& output) { output = x ^ 2; }

“&”表示輸出參數是對應該存儲輸出的存儲位置的引用。 它是C ++中的語法糖,等效於此“ C”代碼:

void foo(double x, double* pointer_to_output) { *pointer_to_output = x ^ 2; }

指針取消引用被引用語法隱藏,但是思想是相同的。

數組執行類似的語法技巧,它們實際上作為指針傳遞,因此

void foo(double x[3], double output[3]) { ... }

void foo(double* x, double* output) { ... }

基本相同。 請注意,無論哪種情況,都無法確定數組的大小。 因此,通常認為傳遞指針和長度是一種好的做法:

void foo(double* x, int xlen, double* output, int olen);

這樣的輸出參數在多種情況下使用。 一種常見的方法是返回多個值,因為函數的返回類型只能是單個值。 (雖然您可以返回包含多個成員的對象,但是不能直接返回多個單獨的值。)使用輸出參數的另一個原因是速度。 如果所討論的對象較大且/或構造成本很高,則通常可以更快地在適當位置修改輸出。

另一個編程范例是返回一個指示函數成功/失敗的值,並在輸出參數中返回計算值。 例如,許多歷史悠久的Windows API都以這種方式工作。

數組是低級C ++構造。 它可以隱式轉換為指向為數組分配的內存的指針。

int a[] = {1, 2, 3, 4, 5};
int *p = a; // a can be converted to a pointer
assert(a[0] == *a);
assert(a[1] == *(a + 1));
assert(a[1] == p[1]);
// etc.

關於數組的令人困惑的事情是函數聲明void foo(int bar[]); 等同於void foo(int *bar); 所以foo(a)不會復制數組a 而是將a轉換為指針,然后復制該指針(而不是內存)。

void foo(int bar[]) // could be rewritten as foo(int *bar)
{
    bar[0] = 1; // could be rewritten as *(bar + 0) = 1;
}

int main()
{
    int a[] = {0};
    foo(a);
    assert(a[0] == 1);
}

bar指向相同存儲器a確實如此修改數組的內容指向bar相同修改數組的內容a

在C ++中,您還可以按引用傳遞對象( Type &ref; )。 您可以將引用視為給定對象的別名 因此,如果您寫:

int a = 0;
int &b = a;
b = 1;
assert(a == 1);

b實際上是一個別名a -通過修改b修改a ,反之亦然。 函數也可以通過引用來接受參數:

void foo(int &bar)
{
    bar = 1;
}

int main()
{
    int a = 0;
    foo(a);
    assert(a == 1);
}

同樣, bar僅僅是a的別名,因此通過修改bar您還將修改a


您擁有的數學例程庫正在使用這些功能將結果存儲在輸入變量中。 這樣做是為了避免復制並簡化內存管理。 如@Baum mit Augen所述,該方法還可以用作返回多個值的一種方法。

考慮以下代碼:

vector<int> foo(const vector<int> &bar)
{
    vector<int> result;
    // calculate the result
    return result;
}

在返回resultfoo將復制該向量,並且根據所存儲元素的數量(和大小),該副本可能非常昂貴。

注意:大多數編譯器會的Elid復制上述使用命名返回值優化(NRVO)中的代碼。 但是,在一般情況下,您無法保證會發生這種情況。

避免昂貴拷貝的另一種方法是在heap上創建結果對象,並返回指向已分配內存的指針:

vector<int> *foo(const vector<int> &bar)
{
    vector<int> *result = new vector<int>;
    // calculate the result
    return result;
}

調用方需要管理返回對象的生存期,在不再需要它時調用delete 否則可能會導致內存泄漏 (內存保持分配狀態,但實際上無法被應用程序使用)。

注意:有多種解決方案可幫助返回(昂貴的復制)對象。 C ++ 03具有std::auto_ptr包裝器,可幫助您對在堆上創建的對象進行生命周期管理。 C ++ 11在語言中添加了移動語義 ,從而允許通過值而不是使用指針來有效地返回對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM