【问题标题】:const to Non-const Conversion in C++C++ 中 const 到非 const 的转换
【发布时间】:2011-11-10 18:45:17
【问题描述】:

这些天我对const 关键字感到非常恼火,因为我不太熟悉它。我有一个存储所有 const 指针的向量,例如 vector<const BoxT<T> *> *Q_exclude,在另一个类的构造函数中,我需要将此队列中的一个元素作为参数传入并将其分配给非常量成员。我的问题是:

如何将 const 变量分配给非 const 变量?我知道这没有意义,因为毕竟 const 是 const,不应该以任何方式改变。但是那个烦人的成员变量真的必须在这个过程中改变!我也可能将向量中的数据类型更改为非常量,但这将是太多的工作。或者有谁知道如何避免这种情况?

【问题讨论】:

  • 如果要更改它们指向的对象,为什么要存储指向 const 的指针?
  • 也许发布一些代码......但正如 RMF 所说,这看起来像不幸的设计。
  • “但是那个烦人的成员变量真的必须在这个过程中改变!”那你为什么把它设为const 成员变量呢?如果您发现自己需要修改 const 的内容,那么这表明存在设计问题。要么你不应该修改它,要么你应该重新考虑它是否真的是const
  • C++ 可能存在一些问题:您可能希望数据在某些函数中为 const,而在其他函数中为非 const。但是,对于vector,要么全有,要么全无。 - 无论如何,你不需要做所有你能做的事情。 IMO,如果您可以传递 const 引用(以提高性能),那就足够了。
  • @UncleBens:存储非const 元素,然后将整个向量作为const 传递到元素访问不应可变的上下文中。简单!

标签: c++ constants


【解决方案1】:

您可以将const 对象分配给非const 对象就好了。因为您正在复制并因此创建了一个新对象,所以不会违反constness。

Like so:

int main() {
   const int a = 3;
   int b = a;
}

It's different如果你想获得一个指针或引用原来的const对象:

int main() {
   const int a = 3;
   int& b = a;       // or int* b = &a;
}

//  error: invalid initialization of reference of type 'int&' from
//         expression of type 'const int'

如果你真的必须的话,你可以使用const_cast 来绕过类型安全,但请记住你正在这样做:摆脱类型安全。在the below example 中修改ab仍然未定义:

int main() {
   const int a = 3;
   int& b = const_cast<int&>(a);

   b = 3;
}

尽管它编译时没有错误,但任何事情都可能发生,包括打开黑洞或将您辛苦赚来的所有积蓄转入我的银行账户。

如果你已经达到了你认为这样做的必要条件,我会紧急重新审视你的设计,因为它有很大的问题。

【讨论】:

  • 我见过的最清晰的评论。你已经两次救了我的命
  • 现在我正在记下您的完整评论。哈哈
  • +1 表示任何事情都可能发生,包括打开黑洞或将您辛苦赚来的所有积蓄转入我的银行账户。一如既往的好答案!!!
  • @Destructor:需要注意的是,尽管 UB 代码在 Stack Overflow 上很流行,但我的银行账户中还没有出现任何人来之不易的积蓄。 :(
【解决方案2】:

更改常量类型将导致未定义行为

但是,如果您有一个由指向 const 的指针指向或由指向 const 的引用引用的原始非 const 对象,那么您可以使用 const_cast 来摆脱那个常数。

抛弃 constness 被认为是邪恶的,应该避免 not。如果你想通过它修改数据,你应该考虑将你在vector中使用的指针类型更改为非常量。

【讨论】:

  • “被认为是邪恶的,不应回避”——那么你是斯莱特林?
【解决方案3】:

抛弃指针常量的实际代码是:

BoxT<T> * nonConstObj = const_cast<BoxT<T> *>(constObj);

但请注意,这确实是作弊。更好的解决方案是弄清楚为什么要修改 const 对象,并重新设计代码,这样您就不必……或者从向量中删除 const 声明,如果事实证明您没有毕竟真的希望这些项目是只读的。

【讨论】:

  • 您根本没有得到“非 const 对象”。你得到一个非常量类型的变量,但它作为句柄的对象仍然是不可变的
  • @Tomalak:如果它以前是不可变的,那就是。如果它以前是可变的,那么它仍然是可变的并且你有办法修改它,这就是这种 const-cast 恶作剧变得诱人的原因。
【解决方案4】:

这里留给我自己,

如果我收到此错误,我可能在应该使用 char* const 时使用了 const char*

这使得指针不变,而不是字符串的内容。

const char* const 使得值和指针也是常量。

【讨论】:

  • 哈哈,顺便说一句,你可能会为此使用 cmets
【解决方案5】:
void SomeClass::changeASettingAndCallAFunction() const {
    someSetting = 0; //Can't do this
    someFunctionThatUsesTheSetting();
}

另一个解决方案是在对 const 函数使用的变量进行编辑之间调用所述函数。这个想法解决了我的问题,因为我不倾向于更改函数的签名,而不得不使用“changeASettingAndCallAFunction”方法作为中介:

当您调用该函数时,您可以在调用之前先对设置进行编辑,或者(如果您不倾向于弄乱调用位置)也许调用您需要更改要传播的变量的函数(就像我的情况一样)。

void SomeClass::someFunctionThatUsesTheSetting() const {
     //We really don't want to touch this functions implementation
     ClassUsesSetting* classUsesSetting = ClassUsesSetting::PropagateAcrossClass(someSetting);
     /*
         Do important stuff
     */
}

void SomeClass::changeASettingAndCallAFunction() const {
     someFunctionThatUsesTheSetting();
     /*
         Have to do this
     */
}

void SomeClass::nonConstInvoker(){
    someSetting = 0;
    changeASettingAndCallAFunction();
}

现在,当调用“someFunctionThatUsesTheSetting”的某些引用时,它将调用更改为 someSetting。

【讨论】:

    猜你喜欢
    • 2012-03-14
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-05
    相关资源
    最近更新 更多