当概念上不是

时间:2018-02-07 15:03:00

标签: c++ c++11 const

就我在这里和那里阅读而言,应尽可能使用const。但是,我有一个总是困扰我的案例。

如果成员函数没有改变任何成员变量值,但它在概念上不是const函数,我应该将其标记为const吗?

例如:

class Engine{
public:
    int status;
};

class Car{
public:
   void start() const{
        engine_->status = 1;
    }
private:
    std::unique_ptr<Engine> engine_;
};

编译器将接受start()的{​​strong> constness ,因为engine_指针没有改变。然而,至少IMO似乎是不现实的,在名为start的类中称为Car的函数是const

这个例子只是一个快速的例子。通常,Car类的某些内部状态应相应更新,使const关键字不可行。然而,这个小例子只是为了说明我的想法。

4 个答案:

答案 0 :(得分:14)

函数是否应为const的一个简单指标是:

Type a{...};
Type b{...};

bool comp1 = a == b;

b.some_func(...);

bool comp2 = a == b;

如果comp1comp2 不同,则some_func不是const

显然,并非每种类型都有operator==超载,但大多数都至少有一个概念性的想法,即你会测试它们是否相等。具有不同Car个状态的不同engine个实例将不相等。因此,更改engine状态的函数不是const

答案 1 :(得分:5)

在你的情况下,编译器允许你使start() const由于通过指针的不完美的constness传播。如果用Engine类型的对象替换指针,则问题将消失。所以答案是否定的,在这种情况下它不应该是const,因为使用Engine作为智能指针或实例是内部细节,不应该影响类Car的公共接口。

  

据我所知,在可能的情况下应使用const。

这种陈述过于笼统,与任何通用建议一样,不应在每种情况下正式使用。

答案 2 :(得分:4)

在您的示例中,您可能需要std::experimental::propagate_const

class Car{
public:
   void start() { engine_->status = 1; }
private:
    std::experimental::propagate_const<std::unique_ptr<Engine>> engine_;
};

然后您的start不再是const

答案 3 :(得分:3)

const的含义可能会有所不同。

  • 如果保留const,则为==

  • 如果您的类型遵循引用语义并且它不会更改所引用的内容,则某些内容为const

  • 如果可以合理的方式在任何右值或左值上使用,则constconst

  • 如果从多个线程使用它是安全的,那么它是const

  • 如果汇编为const,则为const

  • 如果对象声称的内部状态不是由内部变异的,则为const

所有这些都是合理的规则来决定方法或参数是否是T const*

要特别小心的是要了解T*constconst iterator之间的区别,并且不要将顶级const作为内部const。它不是const_iterator const gsl::span<int>。它不是gsl::span<const int>,而是const unique_ptr<T>。它不是unique_ptr<T const>,而是vector

另一方面,vector<const T>是一个值语义类型;它假装它的缓冲区是它的一部分(即使这是谎言)。它不是const vector<T>,而是<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.mehmet.catchtheball.main"> <RelativeLayout android:id="@+id/relativeLayout" android:layout_width="match_parent" android:layout_height="match_parent"/> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:onClick="undo" android:text="@string/undo" /> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/button" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_marginLeft="27dp" android:layout_marginStart="27dp" tools:textColor="@android:color/background_dark" /> </RelativeLayout>