类构造函数,析构函数和运算符重载的实用函数 [英] Utility functions for class constructors, destructor, and operator overloading
问题描述
前一段时间,我在网站上发现一些实用函数的代码示例,用于创建
,销毁
对象,甚至当重载一些运算符
时。
更精确地说,主要使用以下成员函数: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 theconstructors
, e.g. thedefault
orparameter constructor
. - The
copy
member function is used to do adeep copy
of an object passed as aconst reference
. It is called inside thereference constructor
and the overload of theoperator =
. - The
set
member function which mainlyallocates
memory for theprivate members
that require it. - Finally, the
destroy
member function is used forreleasing
the allocated memory. It's called, for example, inside of thedestructor
.
有你的意见,知道这是否是一个良好的编程实践?哪些是好处或缺点?欢迎任何意见和建议!
下面,我说明如何为 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屋!