在分配对象时保持恒定性
Preserve constness on assigning an object
分配时是否可以保持对象的恒定性?考虑一个保存指向动态内存的指针的类,作业时需要软拷贝。(有一些更复杂的逻辑,包括引用计数,但它与问题无关)。
class Vec {
private:
int *data_; // dynamic array
public:
int * Data() { return data_;} // access for modification
const int * Data() const { return data_;} // read only access
Vec subVec(int pos) { // create writable submat
Vec ret;
ret.data_ = &data_[pos];
return ret;
}
const Vec subVec(int pos) const { // create read only submat
Vec ret;
ret.data_ = &data_[pos];
return ret;
}
};
void processVec(const Vec & src) {
src.Data()[0] = 1; // not allowed, since src const
Vec subVec = src.subVec(2); // call const version of subVec and create
// a soft copy - wrapper for a part of array.
// Assignment creates a copy, which removes constness
subVec.Data()[0] = 1; // allowed! Since subVec is a copy, but modifies
// identical dynamic memory from the wrapped src!
}
我希望subVec.Data()[0] = 1;
失败,因为它应该保持恒定。
你的问题是,你正在定义一个指向某个对象的智能指针,但你混淆了智能指针的恒常性(类似于Foo* const bar;
)和对象的恒常性(类似于const Foo* bar;
)。您需要的是将指针的常常性与对象的恒常性分开。
通过使用两个智能指针类而不是一个,可以相对轻松地做到这一点:一个基类,它为const
对象实现智能指针,另一个派生类,它为非const
对象实现智能指针。
有了它,你总是可以将你的智能指针降级到"const"基类,制作无拷贝的"const"副本等。您甚至可以向派生的非"const"智能指针类添加一个构造函数,该类采用"const"基类的智能指针来创建数据的深层副本。
我会通过在
处理 const 或非 const 对象时创建不同的返回类型来模仿iterator
和const_iterator
习语。这里有一个为常量调用subVec
实现不同类型的示例:
class Vec {
// ...
public:
// ...
const int * Data() const { return data_;} // read only access
Vec subVec(int pos) { // create writable submat
Vec ret;
ret.data_ = &data_[pos];
return ret;
}
class SubVec
{
private:
const int* data_;
public:
SubVec(const int* data) : data_(data) {}
const int * Data() const { return data_;} // read only access
};
const SubVec subVec(int pos) const { // create read only submat
SubVec ret(&data_[pos]);
return ret;
}
};
这将在 const 情况下生成您想要的错误,并将在非 const 情况下进行编译。使用 auto
可以更轻松地编写代码。
IIUC,常量或非常量元素是在运行时分配的,因此类型系统(静态)无法帮助您。您需要为每个元素存储一些布尔标志,并对赋值执行运行时检查以查看它是否允许。
相关文章:
- 将数组的地址分配给变量并删除
- vector.resize()中的分配错误
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- Win32编译器选项和内存分配
- 函数中堆分配的效果与缺少堆分配的情况
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 指针类型类成员的动态强制转换的恒定性是什么?
- 为什么对引用的常量引用会失去其恒定性?
- 运算符的要求<恒定性在标准::stable_sort
- 模板参数推导由于恒定性不一致而失败
- 为什么模板参数失去恒定性?
- 为什么普遍引用不保持其论点的恒定性
- 是否可以使用 SFINAE 检测类方法的恒定性?
- 在模板中强制转换为引用似乎会抛弃恒定性
- 在分配对象时保持恒定性
- 常量成员函数中模板成员的恒定性
- 变量的恒定性及其生存期
- 尊重恒定性,同时避免在堆上重新分配
- 参考类成员的恒定性
- 当函数参数常量引用 T 时,为什么 T 的模板参数推导'skips'数组元素的恒定性?