在下面的C++语句中放置 const 的好地方是什么

what is a good place to put a const in the following C++ statement

本文关键字:const 好地方 是什么 C++ 语句 在下面      更新时间:2023-10-16

考虑以下类成员:

std::vector<sim_mob::Lane *>  IncomingLanes_;

如果我的 Lane 对象,上面的容器将存储指向某些的指针。我不希望使用此变量作为参数的子路由能够修改 Lane 对象。同时,我不知道在哪里放置"const"关键字,这不会阻止我填充容器。

你能帮我这个吗?

谢谢和问候瓦希德

编辑:根据我到目前为止得到的答案(非常感谢他们所有人(假设此示例:

#include <vector>
#include<iostream>
using namespace std;
class Lane
{
private:
    int a;
public:
    Lane(int h):a(h){}
    void setA(int a_)
    {
        a=a_;
    }
    void printLane()
    {
        std::cout << a << std::endl;
    }
};
class B
{
public:
    vector< Lane const  *> IncomingLanes;
    void addLane(Lane  *l)
    {
        IncomingLanes.push_back(l);
    }
};
int main()
{
    Lane l1(1);
    Lane l2(2);
    B b;
    b.addLane(&l1);
    b.addLane(&l2);
    b.IncomingLanes.at(1)->printLane();
    b.IncomingLanes.at(1)->setA(12);
    return 1;
}

我的意思是:

b.IncomingLanes.at(1(->打印通道((

应该在来车道上工作没有问题,并且

b.IncomingLanes.at(1(->集A(12(

不应该被允许。(在上面的例子中,提到的两种方法都不起作用!

除了解决问题之外,我还在寻找良好的编程实践。因此,如果您认为上述问题有解决方案,但方式不好,请让我们都知道。Thaks Again

先绕道而行:使用智能指针,例如shared_ptr,而不是容器中的原始指针。这将使您的生活变得轻松得多。

通常,您正在寻找的内容称为design-const,即不修改其参数的函数。这是,你通过const-reference传递参数来实现的。此外,如果它是一个成员函数,则使函数const(即 this在此函数的范围内变得const,因此不能使用 this 写入成员(。

如果不更多地了解您的班级,就很难建议您使用const-reference的容器到车道。这将使插入lane对象变得困难 - 一次性事件,只能通过ctor中的初始值设定项列表来实现。

一些必读:

  • 整个常见问题 18
  • 萨特论常量正确性

编辑:代码示例:

#include <vector>
#include <iostream>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
#include <vector>
#include <iostream>
#include <memory>
//using namespace std; I'd rather type the 5 characters
// This is almost redundant under the current circumstance
class Lane
{
private:
    int a;
public:
    Lane(int h):a(h){}
    void setA(int a_) // do you need this?
    {
        a=a_;
    }
    void printLane() const // design-const
    {
        std::cout << a << std::endl;
    }
};
class B
{    
    // be consistent with namespace qualification
    std::vector< Lane const * > IncomingLanes; // don't expose impl. details
 public:
    void addLane(Lane const& l) // who's responsible for freeing `l'?
    {
        IncomingLanes.push_back(&l); // would change
    }
    void printLane(size_t index) const
    {
#ifdef _DEBUG 
        IncomingLanes.at( index )->printLane();
#else
        IncomingLanes[ index ]->printLane();
#endif
    }        
};
int main()
{
    Lane l1(1);
    Lane l2(2);
    B b;
    b.addLane(l1);
    b.addLane(l2);
    //b.IncomingLanes.at(1)->printLane(); // this is bad
    //b.IncomingLanes.at(1)->setA(12); // this is bad
    b.printLane(1);
    return 1;
}

此外,正如Matthieu M.所建议的那样:

共享所有权更加复杂,因为它变得困难 告诉谁真正拥有该对象以及何时发布该对象(以及 这是在性能开销之上(。所以unique_ptr应该是 默认选择,shared_ptr最后的手段。

请注意,unique_ptr可能需要您使用 std::move 移动它们。我正在更新示例以使用pointer to const Lane(一个更简单的入门界面(。

你可以这样做:

std::vector<const sim_mob::Lane *>  IncomingLanes_;

或者这样:

std::vector<sim_mob::Lane const *>  IncomingLanes_;

C/C++中,const typename * 和typename const * 在含义上是相同的。

已更新以解决更新的问题:

如果你真的需要做的是

b.IncomingLanes.at(1)->printLane()

那么你只需要像这样声明printLane

void printLane() const // Tell compiler that printLane doesn't change this
  {
  std::cout << a << std::endl;
  }

我怀疑您希望对象能够修改元素(即,您不希望元素真正const(。 相反,您希望非成员函数仅获得对std::vector的只读访问权限(即,您希望禁止来自对象外部的更改(。

因此,我不会把const放在IncomingLanes_的任何地方。 相反,我会将IncomingLanes_公开为一对std::vector<sim_mob::Lane *>::const_iterator(通过称为 GetIncomingLanesBegin()GetIncomingLanesEnd() 之类的方法(。

你可以这样声明它:

std::vector<const sim_mob::Lane *>  IncomingLanes_;

您将能够在数组中添加或删除项目,但您希望能够更改项目,请参阅下面的内容

   IncomingLanes_.push_back(someLine); // Ok
   IncomingLanes_[0] = someLine; //error
   IncomingLanes_[0]->some_meber = someting; //error
   IncomingLanes_.erase(IncomingLanes_.end()); //OK
   IncomingLanes_[0]->nonConstMethod(); //error

如果您不希望其他例程修改 IncomingLanes,但您确实希望能够自己修改它,只需在调用的函数声明中使用 const

或者,如果您无法控制这些功能,当它们位于外部时,请不要直接授予它们对 IncomingLane 的访问权限。将 IncomingLanes 设为私有,并为其提供持续获取器。

我认为如果不将指针存储在向量常量中,您想要的是不可能的。

 const std::vector<sim_mob::Lane*> // means the vector is const, not the pointer within it
 std::vector<const sim_mob::Lane*> // means no one can modify the data pointed at.

充其量,第二个版本可以执行您想要的操作,但是无论要修改数据,您都会在整个代码中使用此构造:

 const_cast<sim_mob::Lane*>(theVector[i])->non_const_method();

您是否考虑过不同的类层次结构,其中 sim_mob::Lane 的公共接口是 const 和 sim_mob::Really_Lane 包含非 const 接口。那么矢量的用户在不使用dynamic_cast的情况下无法确定"车道"对象是否"真实"?

在我们讨论const优点之前,您应该首先使用封装

不要vector暴露给外部世界,它会变得容易得多

这里的弱 (*( 封装就足够了:

class B {
public:
    std::vector<Lane> const& getIncomingLanes() const { return incomingLanes; }
    void addLane(Lane l) { incomlingLanes.push_back(l); }
private:
    std::vector<Lane> incomingLanes;
};

以上是简化的,但实现了目标:

  • 类的客户端无法修改vector本身
  • 类的客户端无法修改vector内容(Lane实例(

当然,该类可以完全访问vector内容并随意修改它。

您的新main例程变为:

int main()
{
    Lane l1(1);
    Lane l2(2);
    B b;
    b.addLane(l1);
    b.addLane(l2);
    b.getIncomingLanes().at(1).printLane();
    b.getIncomingLanes().at(1).setA(12); // expected-error
        // { passing ‘const Lane’ as ‘this’ argument of
        //   ‘void Lane::setA(int)’ discards qualifiers }
    return 1;
}

(*(从某种意义上说,即使属性本身没有暴露,这也是很弱的,因为我们在实践中向外部世界提供了对它的引用,客户端并没有真正被屏蔽。