将const放在以下C ++语句中的好地方是什么?

时间:2012-05-03 07:48:40

标签: c++

考虑以下类成员:

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) - &GT; printLane()

应该在没有问题的IncomingLanes上工作

  

b.IncomingLanes.at(1) - &GT;组A(12)

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

除了解决问题之外,我也在寻求良好的编程实践。因此,如果你认为上述问题有一个解决办法,但方法不好,请让我们都知道。 Thaks agian

7 个答案:

答案 0 :(得分:3)

首先绕道而行:使用智能指针shared_ptr而不是容器内的原始指针。这将使你的生活变得轻松起来。

通常,您要查找的内容称为design-const,即不修改其参数的函数。通过const-reference传递参数,实现这一点。此外,如果它是成员函数,则函数const(即this在此函数的范围内变为const,因此您无法使用this向成员写入)。

在不了解您的课程的情况下,很难建议您使用const-reference s的容器进行通道。这将导致插入lane对象变得困难 - 一次性事件,只能通过ctor中的初始化列表进行。

一些必读:

编辑:代码示例:

#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(一个更简单的界面来开始)。

答案 1 :(得分:2)

你可以这样做:

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;
  }

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

您可以声明:

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

答案 4 :(得分:0)

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

或者,如果您无法控制这些功能,那么当它们处于外部时,请不要直接授予他们访问IncomingLanes的权限。将IncomingLanes设为私有并为其提供const getter。

答案 5 :(得分:0)

如果不将指针存储在矢量const中,我认为你不想要的是什么。

 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的情况下,向量的用户不能确定“Lane”对象是“真实的”吗?

答案 6 :(得分:0)

在我们达到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;
}

(*)这是,即使属性本身未公开,因为我们在实践中向外部世界提供了对它的引用,客户端并没有真正被屏蔽。