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

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

问题描述

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



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



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

  #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<向量< short> > getMatrixFromFile(string fName);
void showMatrix(vector< vector< short>> mat);
vector< unsigned int> DFS(vector< vector< short> mat);

/ *从文件读取矩阵(fName)* /
vector<向量< short> > getMatrixFromFile(string fName)
{
unsigned int mDim;
ifstream in(fName.c_str());
在>> mDim;
vector<向量< short> > mat(mDim,vector< short>(mDim));
for(int i = 0; i for(int j = 0; j in> ; mat [i] [j];
}
}
return mat;
}

/ *输出矩阵到stdout * /
void showMatrix(vector< vector< short>> mat){
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){
//当访问
时给出DFS的顺序< unsigned int> nodeStack;
//跟踪已访问的节点
向量< bool> visited(mat.size(),false);
vector< unsigned int>结果;
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 if(1 == mat [cIdx] [i]& ){
nodeStack.push(i);
visited [i] = true;
}
}
}
return result;
}

int main()
{
vector<向量< short> >垫;
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);
}

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



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



C ++中的二维数组有向量和类型**的标准替代方案吗?



LATER EDIT:



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

/ **
*在图形周围包装
** /
模板< class T>
class SGraph
{
private:
size_t nodes;
vector< T>帕马特里克斯
public:
SGraph():nodes(0),pmatrix(0){}
SGraph $ b //从文件名初始化图形
SGraph(string& file_name);
void resize(size_t new_size);
void print();
void DFS(vector< size_t>& results,size_t start_node);
//用于检索索引。
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());
在>>节点;
pmatrix = vector< T>(nodes * nodes);
for(int i = 0; i for(int j = 0; 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 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>访问(节点*节点,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 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引用。



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



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

  typedef向量< short>行; 
typedef vector< Row>方矩阵;
void showMatrix(const SquareMatrix& mat);

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



现在让我们来看看getMatrixFromFile:

  SquareMatrix getMatrixFromFile(string fName); 

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

  SquareMatrix& getMatrixFromFile(const string& fName); 

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

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

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



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

$ b $


  1. 如果函数只需要从中读取则通过const引用。

  2. 如果函数需要修改


  3. 仅当 b $ b

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


    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.

    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 .

    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 ?

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

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

    LATER EDIT:

    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.

    This is my latest code:

    #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);
    }
    

    解决方案

    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.

    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.

    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);
    

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

    Now let's look at getMatrixFromFile:

    SquareMatrix getMatrixFromFile(string fName);
    

    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);
    

    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. 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.

    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天全站免登陆