C++ 临时修改常量参数

C++ 临时修改常量参数,c++,C++,我有一个函数,它在概念上不应该修改参数。parameter对象是一个大对象(一个10000或更多的向量),所以我不想创建副本。在C++中做这件事的道德方法是什么?< /P> double computeDelta(const vector< double > &grid, unsigned int index, double newvalue) { // compute something on old grid double oldvalue = gr

我有一个函数,它在概念上不应该修改参数。parameter对象是一个大对象(一个10000或更多的向量),所以我不想创建副本。在C++中做这件事的道德方法是什么?< /P>
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
}
double computeDelta(常量向量&网格,无符号整数索引,双newvalue){
//在旧网格上计算一些东西
double oldvalue=网格[索引]
//临时更改网格
grid[index]=newvalue;//这是非法的,因为const(怎么做是个问题)
//在新的网格上计算一些东西
//恢复原始网格
网格[索引]=旧值
return//新旧事物的区别
}

只需从函数声明中删除
const
修饰符。

您可以使用const\u 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
}
double computeDelta(常量向量&网格,无符号整数索引,双newvalue){
//在旧网格上计算一些东西
双oldvalue=网格[索引];
//临时更改网格
const_cast(grid)[index]=newvalue;
//恢复原始网格
const_cast(grid)[索引]=旧值;
return//新旧事物的区别
}

首先,不要修改向量-在您的简单示例中,我不明白为什么不能只处理临时变量

但是const_cast可以说是正确的做法,因为在这种情况下,你需要明智地“欺骗”const ness。请注意,这将在多线程下中断,因为您的客户机代码可能假定您没有修改向量,但您正在修改。如果中途抛出异常,也就是说,如果不小心保证原子性,它也会中断


最安全的做法-只需删除
常量
声明,并在注释中解释它是如何修改的,即中间修改的。

删除
常量
,并小心地清理


如果您使用的是
const
引用参数,则保证不会更改它。如果你开始改变它,首先,这可能会在多线程程序中很好地打破,其次,OT也可能是向量在一些只读空间中。(注:我知道这是非常棘手的C++技术,但我可以看到一个C++ 11编译器,它可以创建一个初始化向量在只读空间)-在这种情况下,调用函数将崩溃。真的,如果不编译它会更好。

我不认为丢弃常量是个好主意。您可以去掉它,或者如果您想保持常量,可以编写一些适配器代码来处理它。有很多方法可以做到这一点。e、 g

在对向量进行迭代时,如果到达
索引
,则返回特殊值

for (int i = 0; i < grid.size(); ++i) {
    if(i == index) { /* do something with newvalue */ }
    else { /* do something with grid[i] */ }
}
for(int i=0;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];
    }
};
类GridWrapper{
公众:
GridWrapper(const std::vector&grid,unsigned int idx,double val)
:m_grid(grid),m_idx(idx),m_val(val){}
双精度运算符[](无符号整数位置){
如果(pos==m_idx)返回val;
否则返回m_网格[pos];
}
};
或者您可以使用类似于
boost::transform\u迭代器的方法来做同样的事情。

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;
}
double computeDelta(向量网格、无符号整数索引、双新值){
前双精度=计算(网格);
网格[索引]=新值;
double after=计算(网格);
之后返回之前;
}
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;
}
//我就地修改了网格,但承诺在退出之前将其还原
双计算elta(向量和网格、无符号整数索引、双新值){
前双精度=计算(网格);
//如果允许使用C++11 lambda,我们可以做一些更优雅的事情
结构交换程序{
双重价值;
双重价值;
交换程序(双v和双v、双新值):值(v)、旧值(v){
值=新值;
}
~swapper(){value=oldvalue;}
}保护(网格[索引],新值);
double after=计算(网格);
之后返回之前;
}
3.插入一个通读包装器 这是在不强制复制的情况下获取常数引用的唯一安全(常数正确)方法。它要求在容器类型上(或者在迭代器类型上,代理迭代器)模板化计算。尽管避免复制,但根据访问模式,复制速度可能会较慢

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;
}
double computeDelta(向量常量和网格,无符号整数索引,双newvalue){
前双精度=计算(网格);
//假设compute只使用运算符[]
结构覆盖{
向量常数&基;
无符号索引;
双重价值;
叠加(矢量常量和b、无符号i、双v)
:基(b)、索引(i)、值(v){}
双运算符[](向量::大小_类型i)常量{
返回值(i==索引)?值:基[i];
}
vector::size_type size()const{return base.size();}
};
double after=计算(覆盖(网格、索引、新值));
之后返回之前;
}

传递引用足以不复制。只要删除
const
关键字,一切都会好起来的。您可以添加注释来解释为什么const限定与算法的常量概念不匹配。另外,当你做这样的事情时,绝对要确保你是异常安全的。最好是恢复一些析构函数的旧值部分。计算是如何工作的?可能会插入一个通读包装