const有什么问题?

时间:2011-01-12 14:26:21

标签: c++ c++11

C ++和C ++ 0x中const的已知缺点是什么?

12 个答案:

答案 0 :(得分:55)

const唯一的问题是许多开发人员 严重低估了 。它是C ++工具箱中最好的工具之一,非常锋利,但却没有危险。

答案 1 :(得分:49)

主要问题是你必须写它。它应该是默认值,并且应明确指定所有可变变量或参数。

答案 2 :(得分:17)

const的错误在于许多程序员似乎无法完全理解它,而“半常量正确”项目根本不起作用。这是您需要知道的:

  1. Fooconst Foo(或Foo const
  2. Foo&const Foo&(或Foo const&
    • references-to-const绑定到所有类型的东西,而引用到非const的不是
  3. Foo*const Foo*(或Foo const*
    • 指针变量也可以是Foo* constconst Foo* const(或Foo const* const
  4. void Foo::mutator()int Foo::accessor() const的对比
    • 但const成员函数内的指针成员仍然指向非const对象
    • 所以我们可能会意外地从const-function
    • 返回非const数据
  5. iteratorconst_iterator的对比
    • 迭代器变量也可以是const iteratorconst const_iterator
  6. 从没有const概念的语言迁移到C ++非常困难,任何许多人都没有注意到这一点。

答案 3 :(得分:16)

我在新闻组中经常抱怨的两个主要问题是

我认为后者可以/应该得到语言的支持。

可能与对协变成员函数实现的支持相结合,因为两者都需要一些方法来获取this指针的类型。

第三个问题是

干杯&第h。,

答案 4 :(得分:3)

const的问题是程序员错误地使用它我们的不一致

答案 5 :(得分:3)

“错误”的一件事是你不能将T **转换成T const * const *,因为它不危险,所以应该允许这样做。不允许T **转换为T const **是正确的,该转换无效。

我有时会提到const实际上是一种将接口“拆分”为只读方法和编写方法的廉价方法。在C ++中它可能是不切实际的。尽管如此,在Java中使用ReadOnly版本的集合会更加实用,因为它们没有const,而且它们的集合类型更加面向对象。

const不会传播:这里的问题是,如果我在我的类中,constness不会被编译器“检查”,即我的接口类可以有一个“const”方法调用非const方法pImpl和编译器不会抱怨。这是因为我的const方法唯一保证不做的是将指针更改为指向不同的对象,而我的pImpl永远不会改变。它甚至可以是一个const指针(不是指向const的指针)。

shared_ptr<T>shared_ptr<const T>之间缺乏适当的协方差也可能是一个问题,虽然总的来说我已经看到不是问题,但开发人员通常会输入他们的shared_ptrs并且很少typedef shared_ptr为const。并且它们有时会传递const shared_ptr<T> &并认为它们正在传递一个指向const T的共享指针(与const T *一样),它们不是。

答案 6 :(得分:1)

“问题”?

如果您不打算修改传递指针的值(它纯粹用于函数的传递引用输入),请将其标记为const。如果特定变量的值在初始化后不会改变,则同上。如果函数可以安全地调用const类实例,请将其标记为const。正确注释的项目越多const,您在无意中犯错的可能性就越小,理论上在没有完整知识的情况下编译器能够执行的优化程度越高(例如在仅使用函数原型进行编译时) )。

当您尝试将const变量转换为非const变量时,现代版本的gcc支持警告。我建议你启用这些警告。

唯一需要注意的是你正在标记的 const; const char * foo()char * foo() const不同。

答案 7 :(得分:0)

另一个尚未提及的问题是设计糟糕的界面可能会破坏const(即使没有强制转换)。

示例:

class TreeNode {
public:
    TreeNode& getParent() const { return *parent_; }
    TreeNode& getLeft()   const { return *left_;   }
    TreeNode& getRight()  const { return *right_;  }
private:
    //TreeNode has a pointer to the Tree to enable navigation of the tree.
    //Assume that other design constraints mean that this must be a pointer 
    //rather than a reference.
    TreeNode* parent_;
    TreeNode* left_;
    TreeNode* right_;
};
//This function demonstrates the ability for const to be subverted.
TreeNode& remove_const(TreeNode const& toRemoveConstFrom) {
    TreeNode& parent(toRemoveConstFrom.getParent());
    TreeNode& leftChild(parent.getLeft());
    TreeNode& rightChild(parent.getRight());
    return &toRemoveConstFrom == &leftChild ? leftChild : rightChild;
}

const的不及物性质意味着可以有一个接口,可以从对象的const引用中获取对象的非const引用。在设计接口时需要注意这一点。

答案 8 :(得分:0)

下面的大部分答案陈述了诸如“const的错误是X人做Y”这样的事情。这些不是答案,而是症状。那些const没有问题。 {em>

答案 9 :(得分:0)

const很棒。 const很重要。 const - 正确性是API良好的必要条件。

然而,我曾多次遇到const两个问题。

  • 无法追溯将变量标记为const。您必须声明一个变量代码,在这种情况下,您立即初始化它。但是,如果初始化代码包含if怎么办?您可以选择省略const(不合需要的),使用运算符?而不是if(危害可读性)。 Java是正确的,BTW - const变量不必立即初始化,它们只需要在首次读取之前初始化,并且它们必须在 if的所有分支。

  • 无法指定通过引用函数传递的对象在函数调用期间不会更改。 const T& t 意味着t指向的对象不会更改,而只会使用引用t来更改它。编译器仍然必须假设它没有看到的任何函数调用可能更改对象。在某些情况下,这可以防止相当多的优化。

答案 10 :(得分:-1)

一个问题是该语言还允许你const_cast它,这首先破坏了使用const的目的。

答案 11 :(得分:-2)

有一点是它仍有可能颠覆它。做这样的事情仍然是合法的:

void foo(const inst& x)
{
   const_cast<int&> x = 3;
}

您甚至可以使用memset之类的内容来破坏它而不使用明确的const_cast

这是在编译器强制执行const和为非const感知接口提供一些灵活性之间的权衡。

这导致了另一个限制,因为它没有被普遍接受,这部分是由于另一个问题,即使用const是一个全有或全无的命题。如果您开始使用它,则需要在整个代码库中传播它。