常见错误47:赋值与初始化混淆
从技术视角看去,赋值和初始化没啥关系。它们之间泾渭分明,用在不同的场合。所谓初始化,
就是把一段生鲜存储(raw storage)变成一个对象的过程。对于一个class对象来说,这会
涵盖搭建一系列内部机能,以支持虚函数和虚基类,运行时类型信息以及其他类型相关信息。而
赋值,则是在一个有着合适定义的对象的某种状态上所做的一个变换,是该对象处于一个新
的状态,赋值操作不触及实现对象与类型相关的行为背后的内部机能。赋值操作也从来不会
在一段生鲜存储上实施。
业内有个习惯,即,如果在某些场合下,复制构造语义是不二之选,那么复制赋值语义
则同样也是如影随形,反之亦然。
从技术视角看去,赋值和初始化没啥关系。它们之间泾渭分明,用在不同的场合。所谓初始化,
就是把一段生鲜存储(raw storage)变成一个对象的过程。对于一个class对象来说,这会
涵盖搭建一系列内部机能,以支持虚函数和虚基类,运行时类型信息以及其他类型相关信息。而
赋值,则是在一个有着合适定义的对象的某种状态上所做的一个变换,是该对象处于一个新
的状态,赋值操作不触及实现对象与类型相关的行为背后的内部机能。赋值操作也从来不会
在一段生鲜存储上实施。
业内有个习惯,即,如果在某些场合下,复制构造语义是不二之选,那么复制赋值语义
则同样也是如影随形,反之亦然。
参数的按值传递(时发生的复制操作)是由初始化操作,而非赋值操作完成的。
rawstorage.h
#ifndef RAWSTORAGE_H
#define RAWSTORAGE_H
#include <iterator>
#include <memory>
template <class Out, class T>
class raw_storage_iterator
: public std::iterator<std::output_iterator_tag,void,void,void,void> {
public:
raw_storage_iterator& operator =( const T& element );
explicit raw_storage_iterator( Out cur )
: cur_(cur) {}
raw_storage_iterator& operator *()
{ return *this; }
raw_storage_iterator& operator ++()
{ ++cur_; return *this; }
raw_storage_iterator operator ++( int ) {
raw_storage_iterator tmp( *this );
++*this;
return tmp;
}
protected:
Out cur_;
};
template <class Out, class T>
raw_storage_iterator<Out, T> &
raw_storage_iterator<Out,T>::operator =( const T &val ) {
T *elem = &*cur_; // 取得指向element的指针
new ( elem ) T(val); // placement 复制构造函数
return *this;
}
#endif
rawstorage.cpp
#include "rawstorage.h"
#include <string>
#include <cstdlib>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <memory>
typedef std::string T;
struct X {
X() : t_( new T("C++") ) {}
~X() { delete t_; }
X( const X &that ) : t_( new T(*that.t_) ) {}
X &operator =( const X &rhs ) {
if( this != &rhs )
{ delete t_; t_ = new T(*rhs.t_); }
return *this;
}
const T &get_t() const { return *t_; }
T *t_;
//...
};
std::ostream &operator <<( std::ostream &o, const X &x )
{ return o << *x.t_; }
int main() {
X x;
X *buf = (X *)std::malloc( sizeof(X) ); // raw storage...
X &rx = *buf; // foul trickery...
//rx = x; // probable error!
const int N = 12;
X a[N];
X *ary = (X *)std::malloc( N*sizeof(X) );
//std::copy( a, a+N, ary ); // 向一段生鲜内存赋值
raw_storage_iterator<X *, X> ri( ary );
std::copy( a, a+N, ri ); // works!
std::copy( ary, ary+N, std::ostream_iterator<X>(std::cout,"\n") );
return 0;
}
输出
C++
C++
C++
C++
C++
C++
C++
C++
C++
C++
C++
C++