类构造函数,析构函数和运算符重载的实用函数 [英] Utility functions for class constructors, destructor, and operator overloading

查看:169
本文介绍了类构造函数,析构函数和运算符重载的实用函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前一段时间,我在网站上发现一些实用函数的代码示例,用于创建销毁对象,甚至当重载一些运算符时。
更精确地说,主要使用以下成员函数:init,copy,set和destroy。

A while ago, I found in a website some code examples of utility functions that are used when creating, destructing objects, or even when overloading some of their operators. More precisely, the following member functions are mainly used: init, copy, set, and destroy.


  • $ c> init 成员函数用于初始化所有私有成员。它主要在构造函数内调用,例如。 默认参数构造函数

  • copy 成员函数用于执行深拷贝对象作为 const引用传递。它在引用构造函数内部和 operator = 的重载调用。

  • 设置成员函数主要为分配 private members 需要它。

  • 最后, destroy 成员函数用于释放 。例如,它被称为析构函数

  • The init member function is used to initialize all the private members. It's mostly called inside the constructors, e.g. the default or parameter constructor.
  • The copy member function is used to do a deep copy of an object passed as a const reference. It is called inside the reference constructor and the overload of the operator =.
  • The set member function which mainly allocates memory for the private members that require it.
  • Finally, the destroy member function is used for releasing the allocated memory. It's called, for example, inside of the destructor.

有你的意见,知道这是否是一个良好的编程实践?哪些是好处或缺点?欢迎任何意见和建议!
下面,我说明如何为 CMatrix< T> 类定义这些成员函数。

I would like to have your opinion and know if this is a good programming practice? Which are the benefits or drawbacks? Any comments and suggestions are welcomed! Below, I'm illustrating how those member functions are defined for a CMatrix<T> class.

template < class T >
class CMatrix{

    CMatrix(){ this->initMatrix(); }

    CMatrix(int nRows, int nCols, int nChannels){
        this->initComplexMatrix();
        this->setComplexMatrix(nRows, nCols, nChannels);
    }

    CMatrix(const CMatrix<T> & refMatrix){
        this->initComplexMatrix();
        this->copyComplexMatrix(refMatrix);
    }

    CMatrix<T> & operator = (const CMatrix<T> & refMatrix){
        if(this!=&refMatrix){
            this->destroyComplexMatrix();
            this->initComplexMatrix();
            this->copyComplexMatrix(refMatrix);
        }
        return (*this);
    }

    T & CMatrix<T>::operator()(int, int, int);
    T CMatrix<T>::operator()(int, int, int) const;

    ......

    void initMatrix();
    void copyMatrix(const CMatrix<T> & );
    void setMatrix(int, int, int = 1);
    void destroyMatrix();

    ......

    ~CMatrix(){ this->destroyMatrix(); }

private:
    T *** m_pData;
    int m_nRows;
    int m_nCols;
    int m_nChannels;
};



matrix.cpp



matrix.cpp

#include <matrix.h>

template < class T >
inline T & CMatrix<T>::operator()(int mrow, int mcol, int mchannel){

    assert(mrow >= 0 && mrow < this->getRows());
    assert(mcol >= 0 && mcol < this->getCols());
    assert(mchannel >= 0 && mchannel < this->getChannels());

    return this->m_pData[mrow][mcol][mchannel];
}

template < class T >
void CMatrix<T>::initMatrix(){
    this->m_nRows   = 0;
    this->m_nCols   = 0;
    this->m_nChannels= 0;
    this->m_pData   = NULL;
}

template < class T >
void CMatrix<T>::copyMatrix(const CMatrix<T> & refMatrix){

    if(refMatrix.m_pData!=NULL){

        this->setMatrix(refMatrix.getRows(), refMatrix.getCols(), refMatrix.getChannels());

        for(register int dy=0; dy < this->getRows(); dy++){
            for(register int dx=0; dx < this->getCols(); dx++){
                for(register int ch=0; ch < this->getChannels(); ch++){ 
                    this->m_pData[(dy)][(dx)][(ch)] = refMatrix.m_pData[(dy)][(dx)][(ch)];
                }
            }
        }
    }
    else{
        this->m_pData = NULL;
    }
}

template < class T >
void CMatrix<T>::setMatrix(int nRows, int nCols, int nChannels){

    this->destroyMatrix();

    this->m_pData = NULL;
    this->m_pData = new T ** [nRows];

    for(register int dy=0; dy < nRows; dy++){
        this->m_pData[dy] = NULL;
        this->m_pData[dy] = new T * [nCols];
        for(register int dx=0; dx < nCols; dx++){
            this->m_pData[dy][dx] = NULL;
            this->m_pData[dy][dx] = new T[nChannels];
        }
    }

    this->setRows(mrows);
    this->setCols(mcols);
    this->setChannels(mchannels);
}

template < class T >
void CMatrix<T>::destroyMatrix(){

    if(this->m_pData!=NULL){

        for(register int dy=0; dy < this->getRows(); dy++){
            for(register int dx=0; dx < this->getCols(); dx++){
                delete [] this->m_pData[dy][dx];
            }
            delete [] this->m_pData[dy];
        }

        delete [] this->m_pData;
        this->m_pData = NULL;
    } 
}


推荐答案

否,这是不推荐。你建议的方法不是异常安全的,并且不兼容 const 或需要非默认构造的子对象。

No, this is not recommended. The way you propose is not exception safe and is not compatible with const or subobjects that need non-default construction.

而是使用 ctor-initializer-list 。可以通过在 ctor-initializer-list 中调用的静态辅助函数或通过将逻辑移动到子对象构造函数中来实现代码重用。

Instead use the ctor-initializer-list. Code reuse can be achieved through static helper functions called in the ctor-initializer-list or by moving logic into subobject constructors.

,每个资源使用一个子对象。内存管理逻辑最终在子对象构造函数和析构函数中。在许多情况下,您可以使用库中的现有RAII类,例如 std :: vector ,而不需要自己编写任何内存管理代码。

For memory allocation, use a subobject per resource. The memory management logic ends up in the subobject constructor and destructor. In many cases, you can use existing RAII classes from the library, such as std::vector, and not need to write any memory management code yourself.

大多数运算符都可以使用构造函数中的逻辑,使用复制和交换习语

Most operators can reuse the logic in the constructors, using the copy-and-swap idiom.

编辑:异常安全的结构可能如下所示:

Exception-safe construction might look something like this:

#include <vector>
template<typename T>
class matrix
{
    int m_nCols;
    std::vector<T*> m_rows;
    std::vector<T> m_cells;
    size_t makeIndex( int row, int col ) const { return row*m_nCols + col; }

public:    
    matrix( int nRows, int nCols )
        : m_nCols(nCols), m_rows(nRows), m_cells(nRows * nCols)
    {
        while (nRows--) m_rows[nRows] = &m_cells[nRows * nCols];
    }

    matrix( const matrix<T>& other )
        : m_nCols(other.m_nCols), m_rows(other.m_rows.size()), m_cells(other.m_cells)
    {
        int nRows = other.m_rows.size();
        while (nRows--) m_rows[nRows] = &m_cells[nRows * nCols];
    }

    void swap( matrix& other )
    {
        using std::swap;
        swap(m_nCols, other.m_nCols);
        swap(m_rows, other.m_rows);
        swap(m_cells, other.m_cells);
    }

    matrix& operator=( matrix other )
    {
        other.swap(*this);
        return *this;
    }

    const T& operator()( int row, int col ) const { return m_cells[makeIndex(row,col)]; }
    T& operator()( int row, int col ) { return m_cells[makeIndex(row,col)]; }
};

std :: vector 注意释放内存,并且由于这两个分配是单独的对象,如果 m_cells 无法分配其内存,则 m_rows 将运行,没有任何泄漏。

The std::vector destructor will take care of freeing the memory, and since the two allocations are separate objects, if m_cells fails to allocate its memory, the destructor for m_rows will run and nothing will leak.

当然, std :: vector 这里,固定大小的数组RAII类就足够了。但 std :: auto_ptr 不能与数组一起使用。我认为C ++ 0x应该添加一个标准的固定大小的RAII数组类。

Of course, std::vector is a little bit overkill here, a fixed-size array RAII class would be sufficient. But std::auto_ptr can't be used with arrays. I think C++0x is supposed to add a standard fixed-size RAII array class.

编辑:每个请求,一个3-D版本:

Per request, a 3-D version:

#include <vector>
template<typename T>
class cube
{
    int m_nCols, m_nRows;
    std::vector<T> m_cells;
    size_t makeIndex( int row, int col, int channel ) const { return (channel*m_nRows + row)*m_nCols + col; }

public:    
    cube( int nRows, int nCols, int nChannels )
        : m_nCols(nCols), m_nRows(nRows), m_cells(nRows * nCols * nChannels)
    {
    }

    cube( const cube<T>& other )
        : m_nCols(other.m_nCols), m_nRows(other.m_nRows), m_cells(other.m_cells)
    {
    }

    void swap( cube& other )
    {
        using std::swap;
        swap(m_nCols, other.m_nCols);
        swap(m_nRows, other.m_nRows);
        swap(m_cells, other.m_cells);
    }

    cube& operator=( cube other )
    {
        other.swap(*this);
        return *this;
    }

    const T& operator()( int row, int col, int channel ) const { return m_cells[makeIndex(row,col,channel)]; }
    T& operator()( int row, int col, int channel ) { return m_cells[makeIndex(row,col,channel)]; }

    class channel_iterator
    {
        cube& const cube;
        int const row, col;
        int channel;
        friend class cube;
        channel_iterator( cube& all, int r, int c, int n ) : cube(all), row(r), col(c), channel(n) {}
    public:
        T& operator*() const { return cube(row, col, channel); }
        channel_iterator& operator++() { ++channel; return *this; }
        channel_iterator operator++(int) { return channel_iterator(cube, row, col, channel++); }
        bool operator!=(const channel_iterator& other) const { assert(&cube == &other.cube); return (row == other.row && col == other.col && channel == other.channel); }
    };

    int channel_count() const { return m_cells.size() / m_nRows / m_nChannels; }
    pair<channel_iterator, channel_iterator> range(int row, int col) { return make_pair(channel_iterator(*this, row, col, 0), channel_iterator(*this, row, col, channel_count())); }
};

这篇关于类构造函数,析构函数和运算符重载的实用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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