临时修改const参数
Modifying const parameter temporarily
我有一个函数,它在概念上不应该修改参数。参数对象是一个大对象(一个有10000或更多的向量),所以我不想创建副本。在c++中做这件事的道德方式是什么。
double computeDelta(const vector< double > &grid, unsigned int index, double newvalue) {
// compute something on old grid
double oldvalue = grid[index]
// change grid temporarily
grid[index] = newvalue; // this is illegal because of const (How to do this is question)
// compute something on new grid
// restore original grid
grid[index] = oldvalue
return // difference of old thing and new thing
}
1。按值传递
这保证了完全的安全性,而且很容易。只有在分析表明你真的需要的情况下,才能做一些更复杂的事情
double computeDelta(vector<double> grid, unsigned int index, double newvalue) {
double before = compute(grid);
grid[index] = newvalue;
double after = compute(grid);
return after-before;
}
2.通过非常数引用
这需要调用者信任你,如果有多个线程,他们可能无论如何都必须复制
// I modify grid in-place, but promise to revert it before exiting
double computeDelta(vector<double> &grid, unsigned int index, double newvalue) {
double before = compute(grid);
// we can do something much more elegant if C++11 lambdas are allowed
struct swapper {
double &value;
double oldvalue;
swapper(double &v, double newvalue) : value(v), oldvalue(v) {
value = newvalue;
}
~swapper() { value = oldvalue; }
} guard(grid[index], newvalue);
double after = compute(grid);
return after-before;
}
3.插入一个读穿包装器
这是在不强制复制的情况下获取常量ref的唯一安全(常量正确)方法。它要求在容器类型上模板化计算(或者在迭代器类型上,代之以代理迭代器)。尽管避免了复制,但它可能会更慢,这取决于访问模式
double computeDelta(vector<double> const &grid, unsigned int index, double newvalue) {
double before = compute(grid);
// assuming only operator[] is used by compute
struct overlay {
vector<double> const &base;
unsigned index;
double value;
overlay(vector<double> const &b, unsigned i, double v)
: base(b), index(i), value(v) {}
double operator[] (vector<double>::size_type i) const {
return (i == index) ? value : base[i];
}
vector<double>::size_type size() const { return base.size(); }
};
double after = compute(overlay(grid, index, newvalue));
return after-before;
}
只需从函数声明中删除const
修饰符。
您可以使用const_cast:
double computeDelta(const vector< double > &grid, unsigned int index, double newvalue) {
// compute something on old grid
double oldvalue = grid[index];
// change grid temporarily
const_cast<vector<double>&>(grid)[index] = newvalue;
// restore original grid
const_cast<vector<double>&>(grid)[index] = oldvalue;
return // difference of old thing and new thing
}
首先,不要修改向量-在您的简单示例中,我不明白为什么不能只使用临时变量。
但是const_cast可以说是正确的做法,因为在这种情况下,你需要明智地"欺骗"constness。请注意,这将在多线程下中断,因为您的客户端代码可能会认为您没有修改向量,但您确实在修改。如果中途抛出异常,也就是说,如果不小心保证原子性,它也会崩溃。
最安全的做法是删除const
声明,并解释如何在注释中修改它,即中间修改。
移除const
,并小心清理。
如果你正在使用const
引用参数,你保证不会更改它。如果你开始更改它,首先这可能会在多线程程序中严重中断,其次,向量也可能在某个只读空间中[注意:我知道目前C++技术很难做到这一点,但我可以看到一个C++11编译器计算出它可以在只读空间中创建一个初始化的向量]-在这种情况下,调用函数会崩溃。真的,如果它不编译会更好。
我不认为去掉常量是个好主意。你可以去掉它,或者如果你想保持常量,可以写一些适配器代码来处理它。有很多方法可以做到这一点。例如
在对向量进行迭代时,如果得到index
,则返回特殊值。
for (int i = 0; i < grid.size(); ++i) {
if(i == index) { /* do something with newvalue */ }
else { /* do something with grid[i] */ }
}
或者你可以写一个包装类来做同样的事情
class GridWrapper {
public:
GridWrapper(const std::vector<double>& grid, unsigned int idx, double val)
: m_grid(grid), m_idx(idx), m_val(val) {}
double& operator[](unsigned int pos) {
if (pos == m_idx) return val;
else return m_grid[pos];
}
};
或者你可以使用类似boost::transform_iterator
的东西来做同样的事情。
- 将const引用参数初始化为默认参数会导致悬空引用吗
- 'HMODULE LoadLibraryA(LPCSTR)':无法将参数 1 从 'const _Elem *' 转换为 'LPCSTR'
- 将函数参数"const char*"转换为"std::string_view"是
- 将参数传递为"const"的奇怪效果
- 在函数中使用 const int size 参数创建数组会在 Visual Studio 中抛出错误 C++:表达式的计
- std::span<const T> 作为函数模板中的参数
- 视觉工作室 2017;启用 /permissive 时,类型 "const wchar_t *" 的参数与类型 "PWSTR" 的参数不兼容
- 何时应在构造函数参数中使用 const C++?
- 不允许运算符 const 参数调用 const 成员函数
- std::p ackaged_task 应该删除带有 const 参数的复制 c'tor
- 知道模板参数在编译时是否为 const char*?
- 将对象传递给函数而不将其包装到 std::ref 中,而参数被指定为 const 引用
- 具有参数 (const T *&) 或 (T * &) 或 (const T * const &) 或 (T * const &) 的方法
- 为什么在函数参数前面添加 const 会出错?
- 在函数中使用运算符重载,在 c++ 中使用 const 类型输入参数
- C++ Boost - 序列化错误 - 将"const B"作为"this"参数
- C++ 我应该如何解释函数参数long(*pPointer)(OtherClass *const, long)?
- 什么..表示函数内部参数(const char*值,..)
- 如果参数创建本地副本,则使用参数"const [variable_type] &"的目的是什么?
- 候选函数不可行:第一个参数('const Node *')将失去常量限定符