C ++通过引用传递 [英] C++ pass by reference

查看:167
本文介绍了C ++通过引用传递的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近(4天)开始学习C ++来自C / Java背景。为了学习一种新的语言,我开始重新实现不同的经典算法,因为语言的具体我可以。

I've recently (4 days) started to learn C++ coming from C / Java background. In order to learn a new language I ussualy start by re-implementing different classical algorithms, as language specific as I can.

我来到这个代码,它的一个DFS - 深度优先在未定向图中搜索。仍然从我读的是最好的传递参数在C ++中的引用。不幸的是,我不能完全理解参考的概念。每次我需要一个参考,我很困惑,我认为在指针。在我现在的代码中,我使用传递值。

I've come to this code, its a DFS - Depth First Search in an unoriented graph. Still from what I read it's best to pass parameters by references in C++. Unfortunately I can't quite grasp the concept of reference. Every time I need a reference, I get confused and I think in terms of pointers. In my current code, i use pass by value .

这里的代码(可能不是Cppthonic应该):

Here is the code (probably isn't Cppthonic as it should):

#include <algorithm>
#include <iostream>
#include <fstream>
#include <string>
#include <stack>
#include <vector>

using namespace std;

template <class T>
void utilShow(T elem);

template <class T>
void utilShow(T elem){
    cout << elem << " ";
}

vector< vector<short> > getMatrixFromFile(string fName);
void showMatrix(vector< vector<short> > mat);
vector<unsigned int> DFS(vector< vector<short> > mat);

/* Reads matrix from file (fName) */
vector< vector<short> > getMatrixFromFile(string fName)
{
    unsigned int mDim;
    ifstream in(fName.c_str());
    in >> mDim;
    vector< vector<short> > mat(mDim, vector<short>(mDim));
    for(int i = 0; i < mDim; ++i) {
        for(int j = 0; j < mDim; ++j) {
            in >> mat[i][j];
        }
    }
    return mat;
}

/* Output matrix to stdout */
void showMatrix(vector< vector<short> > mat){
    vector< vector<short> >::iterator row;
    for(row = mat.begin(); row < mat.end(); ++row){
        for_each((*row).begin(), (*row).end(), utilShow<short>);
        cout << endl;
    }
}

/* DFS */
vector<unsigned int> DFS(vector< vector<short> > mat){
    // Gives the order for DFS when visiting
    stack<unsigned int> nodeStack;
    // Tracks the visited nodes
    vector<bool> visited(mat.size(), false);
    vector<unsigned int> result;
    nodeStack.push(0);
    visited[0] = true;
    while(!nodeStack.empty()) {
        unsigned int cIdx = nodeStack.top();
        nodeStack.pop();
        result.push_back(cIdx);
        for(int i = 0; i < mat.size(); ++i) {
            if(1 == mat[cIdx][i] && !visited[i]) {
                nodeStack.push(i);
                visited[i] = true;
            }
        }
    }
    return result;
}

int main()
{
    vector< vector<short> > mat;
    mat = getMatrixFromFile("Ex04.in");
    vector<unsigned int> dfsResult = DFS(mat);

    cout << "Adjancency Matrix: " << endl;
    showMatrix(mat);

    cout << endl << "DFS: " << endl;
    for_each(dfsResult.begin(), dfsResult.end(), utilShow<unsigned int>);

    return (0);
}

你能不能给我一些关于如何使用引用的提示,到这个代码?

Can you please can give me some hints on how to use references, by referencing to this code ?

我当前的编程风格,与C ++的构造兼容吗?

Is my current programming style, compatible with the constructs of C++ ?

C ++中的二维数组有向量和类型**的标准选择吗?

Is there a standard alternative for vector and type** for bi dimensional arrays in C++ ?

LATER EDIT:

确定,我已经分析过您的答案(感谢所有),并以更多的OOP方式重写了代码。我也明白了什么参考和使用它。它类似于一个const指针,除了这个类型的指针可以容纳一个NULL的事实。

OK, I've analyzed your answers (thanks all), and I've rewritten the code in a more OOP manner. Also I've understand what a reference and were to use it. It's somewhat similar to a const pointer, except the fact that a pointer of that type can hold a NULL.

这是我最新的代码:

#include <algorithm>
#include <fstream>
#include <iostream>
#include <ostream>
#include <stack>
#include <string>
#include <vector>

using namespace std;

template <class T> void showUtil(T elem);

/**
* Wrapper around a graph
**/
template <class T>
class SGraph
{
private:
    size_t nodes;
    vector<T> pmatrix;
public:
    SGraph(): nodes(0), pmatrix(0) { }
    SGraph(size_t nodes): nodes(nodes), pmatrix(nodes * nodes) { }
    // Initialize graph from file name
    SGraph(string &file_name);
    void resize(size_t new_size);
    void print();
    void DFS(vector<size_t> &results, size_t start_node);
    // Used to retrieve indexes.
    T & operator()(size_t row, size_t col) {
        return pmatrix[row * nodes + col];
    }
};

template <class T>
SGraph<T>::SGraph(string &file_name)
{
    ifstream in(file_name.c_str());
    in >> nodes;
    pmatrix = vector<T>(nodes * nodes);
    for(int i = 0; i < nodes; ++i) {
        for(int j = 0; j < nodes; ++j) {
            in >> pmatrix[i*nodes+j];
        }
    }
}

template <class T>
void SGraph<T>::resize(size_t new_size)
{
    this->pmatrix.resize(new_size * new_size);
}

template <class T>
void SGraph<T>::print()
{
    for(int i = 0; i < nodes; ++i){
        cout << pmatrix[i];
        if(i % nodes == 0){
            cout << endl;
        }
    }
}

template <class T>
void SGraph<T>::DFS(vector<size_t> &results, size_t start_node)
{
    stack<size_t> nodeStack;
    vector<bool> visited(nodes * nodes, 0);
    nodeStack.push(start_node);
    visited[start_node] = true;
    while(!nodeStack.empty()){
        size_t cIdx = nodeStack.top();
        nodeStack.pop();
        results.push_back(cIdx);
        for(int i = 0; i < nodes; ++i){
            if(pmatrix[nodes*cIdx + i] && !visited[i]){
                nodeStack.push(i);
                visited[i] = 1;
            }
        }
    }
}

template <class T>
void showUtil(T elem){
    cout << elem << " ";
}

int main(int argc, char *argv[])
{
    string file_name = "Ex04.in";
    vector<size_t> dfs_results;

    SGraph<short> g(file_name);
    g.DFS(dfs_results, 0);

    for_each(dfs_results.begin(), dfs_results.end(), showUtil<size_t>);

    return (0);
}


推荐答案

你在做一个伟大的工作。您已经在使用标准容器,算法和编写自己的函数模板。我看到的最缺乏的东西正是参考你的问题:需要通过引用/ const引用。

For 4 days into C++, you're doing a great job. You're already using standard containers, algorithms, and writing your own function templates. The most sorely lacking thing I see is exactly in reference to your question: the need to pass by reference/const reference.

任何时候你传递/返回一个C ++对象值,则调用其内容的深层副本。这不是很便宜,特别是对于像你的矩阵类。

Any time you pass/return a C++ object by value, you are invoking a deep copy of its contents. This isn't cheap at all, especially for something like your matrix class.

首先让我们来看看showMatrix。此函数的目的是输出矩阵的内容。它需要一份副本吗?不,它需要改变矩阵中的任何东西吗?不,它的目的只是显示它。因此,我们想通过const引用传递矩阵。

First let's look at showMatrix. The purpose of this function is to output the contents of a matrix. Does it need a copy? No. Does it need to change anything in the matrix? No, it's purpose is just to display it. Thus we want to pass the Matrix by const reference.

typedef vector<short> Row;
typedef vector<Row> SquareMatrix;
void showMatrix(const SquareMatrix& mat);

[注意:我使用了一些typedef来使这更容易读写。

[Note: I used some typedefs to make this easier to read and write. I recommend it when you have a lot of template parametrization].

现在让我们来看看getMatrixFromFile:

Now let's look at getMatrixFromFile:

SquareMatrix getMatrixFromFile(string fName);

在这里返回SquareMatrix的值可能很昂贵(取决于你的编译器是否应用返回值优化),因此是通过值传递字符串。有了C ++ 0x,我们有右值引用使它,所以我们不必返回一个副本(我也修改了const引用传递的字符串与showMatrix相同的原因,我们不需要一个副本文件名):

Returning SquareMatrix by value here could be expensive (depending on whether your compiler applies return value optimization to this case), and so is passing in a string by value. With C++0x, we have rvalue references to make it so we don't have to return a copy (I also modified the string to be passed in by const reference for same reasons as showMatrix, we don't need a copy of the file name):

SquareMatrix&& getMatrixFromFile(const string& fName);

但是,如果你没有这些特性的编译器,那么一个共同的妥协是传递在矩阵中通过引用并让函数填充它:

However, if you don't have a compiler with these features, then a common compromise is to pass in a matrix by reference and let the function fill it in:

void getMatrixFromFile(const string& fName, SquareMatrix& out_matrix);

这不给客户端提供方便的语法(现在他们必须写两行的代码,而不是一个),但它避免了一致的深度复制开销。还有 MOJO 可以解决这个问题,但是它会随C ++ 0x过时。

This doesn't give provide as convenient a syntax for the client (now they have to write two lines of code instead of one), but it avoids the deep copying overhead consistently. There is also MOJO to address this, but that will become obsolete with C++0x.

一个简单的经验法则:如果你有任何用户定义的类型(不是一个普通的旧数据类型),并且你想传递给一个函数:

A simple rule of thumb: if you have any user-defined type (not a plain old data type) and you want to pass it to a function:


  1. 如果函数只需要从中读取,则传递给const引用。

  2. 如果函数需要修改,


  3. 只有才需要修改副本。

  1. pass by const reference if the function only needs to read from it.
  2. pass by reference if the function needs to modify the original.
  3. pass by value only if the function needs a copy to modify.

有一些例外,你可能有一个便宜的UDT(用户定义类型),它比通过const引用更便宜,例如,但现在坚持这个规则,你会在写作安全,高效的C ++代码的方式,不会浪费宝贵的时钟周期对不必要的副本(一个糟糕的C ++程序的一个普通的麻烦)。

There are exceptions where you might have a cheap UDT (user-defined type) that is cheaper to copy than it is to pass by const reference, e.g., but stick to this rule for now and you'll be on your way to writing safe, efficient C++ code that doesn't waste precious clock cycles on unnecessary copies (a common bane of poorly written C++ programs).

这篇关于C ++通过引用传递的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆