[英]Should the member of class be a pointer?
I'm a bit confused. 我有点困惑。 If you search about the usefulness of (smart) pointers you get very different opinions.
如果你搜索(智能)指针的有用性,你会得到非常不同的意见。 Almost everybody agrees that one should use smart pointers over normal pointers, but there are also many opinions that you should not use pointers at all in modern C++.
几乎每个人都同意应该使用智能指针而不是普通指针,但也有很多意见认为你不应该在现代C ++中使用指针。
Lets consider this abstract situation (Which is similar to my problem): You have one class "Clothes" which has a member of type "Hat" 让我们考虑一下这种抽象情况(类似于我的问题):你有一个类“服装”,其成员类型为“帽子”
class Hat {
public:
enum class HatType{
sombrero,
sun hat,
helmet,
beanie,
cowboy_hat
};
// some functions
private:
HatType type;
// some members
}
class Clothes {
public:
// some functions
private:
Hat currentHat;
// some other members of other types
}
Is there any Difference in run time if I would change Hat
to Hat*
(or a unique_ptr<Hat>
?). 如果我将
Hat
改为Hat*
(或者unique_ptr<Hat>
?),运行时间是否存在差异? (In many functions of Clothes
you would need to call something from Hat
) (在
Clothes
许多功能中你需要从Hat
调用一些东西)
The reason I ask is because there are many different types of hats. 我问的原因是因为有很多不同类型的帽子。 Like sombreros, sun hats, helmets, beanies and cowboy hats.
像阔边帽,太阳帽,头盔,帽子和牛仔帽。 Right now my class hat has an enumerator which stores the hat type.
现在我的班级帽子有一个存储帽子类型的枚举器。 The hat type is only relevant in one specific function of
Hat
but this is the most used function. 帽子类型仅与
Hat
一个特定功能相关,但这是最常用的功能。
Right now I use a simple switch case
in this specific function and based on the hat type the function is evaluated a bit differently. 现在我在这个特定的功能中使用一个简单的
switch case
,并根据帽子类型对该功能的评估略有不同。 This worked fine but I think it would be smarter to simply make an own class for every different hat type which inherit from one single main Hat
class and override the one function. 这工作正常,但我认为简单地为每个不同的帽子类型创建一个自己的类会更聪明,它继承自一个主要的
Hat
类并覆盖一个函数。
To do so I think I would have to change the member currentHat
in Clothes
to any type of pointer. 为此,我想我必须将
Clothes
的成员currentHat
更改为任何类型的指针。 I researched if this would have any negative effects on my performance (I thought about maybe because the location of my currentHat
object and my Clothes
object in memory can be wide apart, but I have no Idea if this would happen and if this would have any negative effects with modern compilers). 我研究过这会对我的表现产生任何负面影响(我想过可能是因为我的
currentHat
对象和我的Clothes
对象在内存中的位置可以分开,但我不知道是否会发生这种情况,如果这会有任何影响现代编译器的负面影响)。
During my research I often read that one should avoid pointers, this made me thinking... some of the information I found was also very old and I do not know if this is outdated. 在我的研究中,我经常读到应该避免使用指针,这让我思考......我发现的一些信息也很老,我不知道这是否已经过时了。 Is there any better way to do this?
有没有更好的方法来做到这一点?
Has anyone any experience with this kind of problem? 有没有人遇到过这种问题? Would be good to get some feedback before I spend a lot of time changing my whole project...
在花费大量时间改变整个项目之前,最好先得到一些反馈......
Side note: I took Clothes
and Hats
only as an examples. 旁注:我只把
Clothes
和Hats
作为例子。 In my real application I have different types and I am creating many million of objects from type Clothes
and I have to call functions of Clothes
which will call functions of Hat
many many million times, that is why I'm concerned with run time. 在我的实际应用程序中,我有不同的类型,我正在创建数百万个类型
Clothes
的对象,我必须调用Clothes
功能,这将称呼Hat
功能数百万次,这就是为什么我关心运行时间。
Edit: Maybe it is also worth noting that I have entirely avoided pointers in my application so far, mostly because I read in some books that one should try to avoid pointers :-) 编辑:也许值得注意的是,到目前为止,我已完全避免在我的应用程序中使用指针,主要是因为我在一些书中读到应该尽量避免使用指针:-)
EDIT2: Thank you for all your answers. EDIT2:谢谢你的所有答案。 Please note that part of my question was not how to do it (although the answers were very useful in that depart) but rather if the performance will suffer from this.
请注意,我的部分问题不是如何做到这一点(虽然答案非常有用)但是如果表现会受此影响。
Ok, let's break down the pointer debacle: 好吧,让我们打破指针崩溃:
new
/ delete
in C++ new
/ delete
There really isn't any exception to this rule. 这个规则确实没有任何例外。 Except if you are writing a library/framework.
除非您正在编写库/框架。 Or some fancy stuff that requires placement new.
或者一些需要放置新东西的花哨的东西。 But in user code
new
/ delete
should be 100% absent. 但在用户代码中,
new
/ delete
应该100%缺席。
This brings us to my next rule: 这将我们带入下一个规则:
This you will find often on the net as the "Don't use raw pointers" advice/rule. 你会经常在网上找到“不要使用原始指针”的建议/规则。 But in my view the problem is not with raw pointers, but with raw pointers that own an object.
但在我看来,问题不在于原始指针,而在于拥有对象的原始指针。
For ownership use smart pointers ( unique_ptr
, shared_ptr
). 对于所有权使用智能指针(
unique_ptr
, shared_ptr
)。 If a pointer is not an owner of the object then it's ok if you use raw pointers. 如果指针不是对象的所有者,那么如果使用原始指针就可以了。 For instance in a tree like structure you can have
unique_ptr
to the children and a raw pointer to the parent. 例如,在树状结构,你可以拥有
unique_ptr
给孩子和一个原始指针父。
You can (arguably) also use a pointer to denote an optional value via nullptr
. 您可以(可以说)使用指针通过
nullptr
表示可选值。
(Well... there are other ways, like type erasure but I won't go there in my post) If you want polymorphism then you can't use a value. (嗯......有其他方法,比如类型擦除,但我不会在我的帖子中去那里)如果你想要多态,那么你就不能使用一个值。 If you can use reference then do, but most of the time you can't.
如果你可以使用参考,那么,但大多数时候你不能。 Which often means you have to use
unique_ptr
. 这通常意味着您必须使用
unique_ptr
。
Here's a breakdown of your three suggested implementations, and some more: 以下是三个建议实现的细分,以及更多:
Hat currentHat;
Hat currentHat;
Clothes
uniquely owns the Hat
Clothes
独特拥有Hat
std::unique_ptr<Hat> currentHat;
std::unique_ptr<Hat> currentHat;
Clothes
still uniquely owns the Hat
Clothes
仍然独特拥有Hat
Hat
Hat
派生的实例 Hat *currentHat;
Hat *currentHat;
Clothes
does not own the Hat
Clothes
不拥有Hat
Hat
outlives the Clothes
Hat
比Clothes
更长 std::shared_ptr<Hat> currentHat;
std::shared_ptr<Hat> currentHat;
Clothes
shares ownership of the Hat
with zero or more other Clothes
Clothes
与零或多个其他Clothes
共享Hat
所有权 std::unique_ptr
otherwise std::unique_ptr
相同 Hat ¤tHat;
Hat ¤tHat;
As you need different Heads, you have basically two options: 由于您需要不同的 Heads,您基本上有两个选择:
1) Using a (smart) pointer, this is well known and easy 1)使用(智能)指针,这是众所周知和容易的
2) Using std::variant 2)使用std :: variant
This is a vary different approach! 这是一种不同的方法! No longer need of a base class and ( pure ) virtual methods.
不再需要基类和(纯)虚方法。 Instead of this using the
std::visit
to access the current object in the tagged union . 而不是使用
std::visit
访问标记联合中的当前对象。 But this comes with a cost: Dispatching in std::visit can be expensive if the compiler did not hardly optimize the call table inside. 但这带来了成本:如果编译器几乎没有优化内部的调用表,那么在std :: visit中调度可能会很昂贵。 But if it can, it is simply taking the tag from the variant and use it as a index to the overloaded function from your visit call, here given as a generic lambda.
但如果可以的话,它只是从变量中获取标记并将其用作访问调用的重载函数的索引,此处作为通用lambda给出。 That is not as fast as indirect call via vtable pointer, but not more than a view instructions more ( if it is optimized!).
这不如通过vtable指针的间接调用快,但不超过视图指令更多(如果它被优化!)。
As always: How you want t go is a matter of taste. 一如既往:你想要的是一个品味问题。
Example: 例:
class Head1
{
public:
void Print() { std::cout << "Head1" << std::endl; }
};
class Head2
{
public:
void Print() { std::cout << "Head2" << std::endl; }
};
class Clothes
{
std::variant<Head1,Head2> currentHead;
public:
Clothes()
{
currentHead = Head1();
}
void Do() { std::visit( [](auto& head){ head.Print();}, currentHead); }
void SetHead( int id )
{
switch( id )
{
case 0:
currentHead= Head1();
break;
case 1:
currentHead= Head2();
break;
default:
std::cerr << "Wrong id for SetHead" << std::endl;
}
}
};
int main()
{
Clothes cl;
cl.Do();
cl.SetHead(1);
cl.Do();
cl.SetHead(0);
cl.Do();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.