2.2 Copy constructor的构造操作

本文探讨了C++中对象拷贝的三种常见情况及其实现机制,包括显式赋初值、作为函数参数和返回值。分析了DefaultMemberwiseInitialization(默认成员初始化)和BitwiseCopySemantics(位拷贝语义)的概念及其应用条件。

一、三种情况下的“一个object的内容会作为另一个object对象的初值”

1.显式赋初值

class X{ ... };
X x;
X xx = x;

2. 作为函数形参

void func(X x);
void bar()
{
    X x;
    //...
    func(x);
    //...   
}

3.当函数返回一个class object时

X foo()
{
    X x;
    //...
    return x;
}

二、Default Memberwise Initialization

该标题的意思是:默认的“为每一个member施以初始化”,那么什么时候才会出发此操作呢?首先看下面的例子:

class String 
{
public:
    // ... 没有explicit copy constructor
private:
    char* str;
    int len;        
};

一个String object 的Dafault Memberwise Initialization发生再这种情况下:

String str("hello world");
String str2 = str;

// 语意相等
str2.str = str.str;
str2.len = str.len;

请记住:

1.如果class没有提供一个explicit copy destructor,当“一个object的内容会作为另一个object对象的初值”时,其内部操作是以Dafault Memberwise Initialization的手法实现,简单粗暴的讲:把每一个内建的或派生的data member的值,从一个object 拷贝到另外一个object 身上。但是,这并不会拷贝其中的member class object,而是以递归的方式施行memberwise initialization。

2.“如果一个class未定义出copy destructor,编译器就自动为它产生出一个。”这句话不对,而应该像ARM所说:Default constructors和Copy constructors在必要的时候才由编译器产生出来。请注意,是在必要的时候。而本节使用的Dafault Memberwise Initialization手法正是不必要合成拷贝构造函数的时候.必要的时候是类没展现出Bitwise Copy Semantics的时候,而本节的String类恰恰展现出了Bitwise Copy Semantics。


三、Bitwise Copy Semantics

该标题的意思是:位逐次拷贝语意。它关系到编译器是否合成一个Copy constructor。首先看下面的这段代码:

#include "Word.h"
Word noun("book");
void foo()
{
    Word verb = noun;
    // ...
}

这里verb由noun初始化而来,但在没有看到Word的声明前,我们是不确定这个初始化操作的程序行为。如果类Word的设计者定义了一个copy constructor,那么verb的初始化会调用该拷贝构造函数;如果该class没定义explicit copy constructor,那么编译器一定会合成一个拷贝构造函数被调用。很遗憾,这是错的。这就是本节讨论Bitwise Copy Semantics的目的。

请记住
如果Word类没有展现 Bitwise Copy Semantics,那么编译器会合成一个拷贝构造函数(用以调用“由编译器合成或设计者显式声明”的member class object的拷贝构造函数);否则,将不合成。


下面来看类是如何表现出Bitwise Copy Semantics的。

// 展现了Bitwise Copy Semantics
class Word
{
public:
    Word(const char*);
    ~Word(){ delete[] str; };
private:
    int cnt;
    char* str;
};

// 未展现Bitwise Copy Semantics
class Word
{
public:
    Word(const String&);
    ~Word();
private:
    int cnt;
    String str;
};

其中String 声明了一个explicit copy constructor:

class String
{
public:
    String(const char*);
    String(const String&);// 声明了显式的拷贝构造函数
    ~String();
    // ...
};

在未展现Bitwise Copy Semantics的情况下,编译器必须合成出一个copy constructor,以便调用member class String object的copy constructor:

// 一个被合成出来的copy constructor
// C++伪码
inline Word::Word(const Word& word)
{
    str.String::String(word.str);
    cnt = word.cnt;
}

什么时候不展现出Bitwise Copy Semantics呢?有以下四种情况

1.当class内含一个member class object而后者的class声明了一个copy constructor(不论是编译器合成或设计者显式声明)时。
2.当class继承自一个base class而后者存在一个copy constructor时(再次强调:不论是编译器合成或设计者显式声明)。以上两种情况下,编译器必须将member或base class 的拷贝构造函数调用操作案查倒被合成的copy constructor中。
3.当class 声明了一个或多个virtual funcitons时。
4.当class派生自一个继承串链,其中有一个或多个virtual base classes时。
下面两种情况比较复杂,接下来讨论。


参考文献:《深度探索C++对象模型》侯捷 译

### RollingGrid 构造函数的定义与使用 `RollingGrid` 的构造函数 `RollingGrid(const Eigen::Vector3i& size)` 主要用于初始化类的成员变量。以下是对其功能的具体说明: #### 参数解释 - **size**: 这是一个三维向量 (`Eigen::Vector3i`),表示体素网格的空间大小。它决定了体素网格在三个维度上的分辨率或范围[^1]。 #### 成员变量初始化 在构造函数内部,通常会执行以下操作: 1. 初始化 `size_`: 将传入的参数 `size` 赋值给私有变量 `size_`,以便后续计算中能够获取到体素网格的尺寸信息。 2. 创建两个独立的体素网格对象: - `grid0_` 和 `grid1_` 是通过标准库中的 `std::unique_ptr` 动态分配内存来创建的。这两个对象分别代表两套不同的体素网格数据结构,允许程序交替更新和访问这两组数据而不会发生冲突。 ```cpp grid0_ = std::make_unique<grid_ns::Grid<int>>(size_); grid1_ = std::make_unique<grid_ns::Grid<int>>(size_); ``` 3. 设置初始使用的体素网格标志位: - 变量 `which_grid_` 会被设置为默认值 (通常是 `false` 或 `true`) 来指示当前正在使用的是哪一个体素网格 (即 `grid0_` 或 `grid1_`)。 4. 清空辅助数组: - 对于动态存储索引映射关系的容器 `updated_indices_` 和 `array_ind_to_ind_`,它们会在构造阶段被清零或者预留一定容量以备后续填充使用。 #### 使用场景 当实例化一个 `RollingGrid` 类型的对象时,调用此构造函数可以指定所需的体素网格空间大小。例如: ```cpp Eigen::Vector3i gridSize(100, 100, 100); RollingGrid rollingGrid(gridSize); ``` 上述代码片段展示了如何利用构造函数创建具有固定大小 `(100x100x100)` 的滚动体素网格对象。 --- ### 示例实现 下面提供了一个可能的完整构造函数实现方式作为参考: ```cpp #include <memory> #include <vector> #include <Eigen/Dense> namespace grid_ns { template<typename T> class Grid { public: explicit Grid(const Eigen::Vector3i &size) : data_(size.prod()) {} private: std::vector<T> data_; }; } class RollingGrid { public: /// @brief Constructor to initialize the RollingGrid with given dimensions. explicit RollingGrid(const Eigen::Vector3i& size); private: Eigen::Vector3i size_; ///< Voxel grid dimension sizes. std::unique_ptr<grid_ns::Grid<int>> grid0_; ///< First voxel grid instance. std::unique_ptr<grid_ns::Grid<int>> grid1_; ///< Second voxel grid instance. std::vector<int> updated_indices_; ///< Indices of recently updated voxels. std::vector<int> array_ind_to_ind_; ///< Mapping between indices and arrays. bool which_grid_; ///< Flag indicating currently active grid. }; // Implementation of constructor RollingGrid::RollingGrid(const Eigen::Vector3i& size) : size_(size), grid0_(std::make_unique<grid_ns::Grid<int>>(size)), grid1_(std::make_unique<grid_ns::Grid<int>>(size)), which_grid_(false) {} // Default starting from 'grid0' ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值