在下面的C++语句中放置 const 的好地方是什么
what is a good place to put a const in the following C++ statement
考虑以下类成员:
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;
}
(*(从某种意义上说,即使属性本身没有暴露,这也是很弱的,因为我们在实践中向外部世界提供了对它的引用,客户端并没有真正被屏蔽。
- 使用静态方法初始化 const 类字段的做法是好是坏
- C const在函数声明中以及其他任何地方的anmpersand的右侧
- 为什么"int & const" MSVC 编译得很好?
- 重载分辨率:调整 const/ref 是否不比用户定义的转换更好?
- 这是检查 const 函数(如果是否创建某些内容)的更好方法
- 返回的const char*不打印好弦(CPP)
- 删除标头中用作函数参数的"primitive"类型前面的"const"是否更好?
- 对于阵列复制,const&的性能更好吗?
- 使用 #defines、枚举值还是 const int 来定义常量值更好
- 数据管理员类型的const校正性 - 更好的解决方案
- 很好的具体地方(书籍/教程)开始用C / C++编程游戏
- 在类中使用'const'和在C++中使用运算符重载是否有一个好的规则?
- 如果在其他地方声明为const,为什么必须在定义时重复const说明符
- 是否有任何情况将对象标记为 const 会导致更好的优化代码(使用优化编译时)
- 我是否应该将 const 用于局部变量以获得更好的代码优化
- const 在不同地方的 C++ 中是什么意思
- 在下面的C++语句中放置 const 的好地方是什么
- 在每个可能的地方使用指针是否是一种好习惯
- Prime生成器:singleton的好地方
- 在合适的地方,在成员函数的末尾添加const是不是一个好习惯?