简体   繁体   English

C++ class 的几个实例(但不是全部)共享一个向量

[英]C++ several instances (but not all) of a class sharing a vector

I want to have a class C , such that instances of C hold a std::vector<int> as a private member.我想要一个 class C ,这样C的实例将std::vector<int>作为私有成员。 Now many instances (but not all) of C will share that vector and keeping a copy for each instance is what I would want to avoid.现在C的许多实例(但不是全部)将共享该向量并且为每个实例保留一个副本是我想要避免的。

If this vector were a single integer for example, I could create a template class for C and have it like this:例如,如果这个向量是单个 integer,我可以为 C 创建一个模板C并像这样:

template <int N>
class C {
 // something
};

If instead of some instances I wanted all instances to share that vector then I would declare the variable static as如果我希望所有实例共享该向量而不是某些实例,那么我会将变量 static 声明为

class C {
    static std::vector<int> _vec;

What I am looking is for something intermediate.我正在寻找的是中间的东西。 I could for example keep a shared_ptr as a private non-static member as in例如,我可以将shared_ptr保留为私有非静态成员,如

class C {
     std::shared_ptr<std::vector<int>> _vec;
}

And that would take care of the lifetime of the object, with some overhead for maintaining shared ownership and also an extra pointer per-instance.这将照顾到 object 的生命周期,有一些维护共享所有权的开销以及每个实例的额外指针。 I could keep a reference instead and let the creator of the instances take care of the lifetime, but avoid the overhead of the shared_ptr .我可以保留一个引用,让实例的创建者负责生命周期,但避免shared_ptr的开销。 Is there a better approach to this design question?这个设计问题有更好的方法吗?

…such that instances of C hold a std::vector as a private member. ...这样 C 的实例将 std::vector 作为私有成员持有。 Now many instances (but not all) of C will share that vector现在 C 的许多实例(但不是全部)将共享该向量

So, that's self-contradicting.所以,这是自相矛盾的。 You can't hold an instance and share the instance safely.您无法持有一个实例并安全地共享该实例。

This is a classical use case of pointers;这是指针的经典用例; even more specifically, classical use case of a shared pointer , as you already noticed.更具体地说,共享指针的经典用例,正如您已经注意到的那样。

I could keep a reference instead and let the creator of the instances take care of the lifetime,我可以保留一个引用,让实例的创建者来处理生命周期,

/me sounds the access-after-destruction alarm /me 发出销毁后访问警报
You're about to find out that won't work.你很快就会发现那是行不通的。 The lifetime is not like you think, but ends when the owning object's lifetime ends.生命周期并不像你想象的那样,而是在拥有对象的生命周期结束时结束。 So, this breaks.所以,这打破了。 (Also, you'll find that under the hood, handing out references compiles down to the same code as handing out raw pointers – it's just safer and does the dereferencing automagically within the language; you're not actually saving a memory indirection there. The classes containing the reference still need to know the address of the object they're handling, and that's the same as having a pointer, if you ask your CPU.) (另外,你会发现在幕后,分发引用编译成与分发原始指针相同的代码——它只是更安全,并且在语言中自动取消引用;你实际上并没有在那里保存 memory 间接寻址。包含引用的类仍然需要知道它们正在处理的 object 的地址,这与拥有一个指针是一样的,如果你询问你的 CPU。)

It breaks, unless the thing handing out the references keeps a count on how many references it handed out, subtracts many references it handed out belong to C instances that were deconstructed, and then deconstructs the vector as soon as that number reaches 0. Take a wild guess what a shared_ptr does!它会中断,除非分发引用的东西对它分发的引用数量进行计数,减去它分发的属于被解构的C实例的引用,然后在该数字达到 0 时立即解构向量。大胆猜测shared_ptr的作用! Exactly this reference counting .正是这个引用计数

Often, however, the access logic is easier;然而,访问逻辑通常更容易; for example,例如,

I have a vector of C , std::vector<C> lexicon , and all held C._vec need to get removed exactly when that full lexicon goes out of scope, so I handle that manually我有一个向量Cstd::vector<C> lexicon ,并且所有持有C._vec需要在完整的lexicon从 scope 中删除时准确删除,所以我手动处理

actually doesn't need reference counting and hence is lower-overhead.实际上不需要引用计数,因此开销较低。 You can indeed solve that by handing out references – but I'd actually prefer to hand out raw pointers in that case: they just as much don't imply ownership, and you don't accidentally make a copy of the std::vector<int> when you pass the pointer by value.你确实可以通过分发引用来解决这个问题——但在那种情况下我实际上更愿意分发原始指针:它们同样不暗示所有权,你不会不小心复制了std::vector<int>当你按值传递指针时。

If your lifetime tracking isn't as easy as that example:如果您的生命周期跟踪不如该示例那么简单:

There's no magic usage tracking in references;参考文献中没有神奇的使用跟踪; and you need something to keep track of whether something is still holding some handle to your individual vector .你需要一些东西来跟踪是否有东西仍然持有你的个人vector的句柄。 That tracking is exactly the "overhead" shared_ptr incurs.该跟踪正是shared_ptr产生的“开销”。 No way around it.没有办法解决它。

A private shared_ptr is hence the right approach:因此,私有shared_ptr是正确的方法:

class C {
  private:
    std::shared_ptr<std::vector<int>> _vec;
}

Your static approach takes you nowhere here - it only makes sense if all , and really all, instances share the same vector which should essentially live from the beginning of time till the end, and even then, it's a bit of a solution that can lead to additional headaches in form of the static initialization order fiasco.您的static方法在这里无处可去-只有当所有实例共享同一个向量时才有意义,该向量基本上应该从时间开始一直存在到结束,即使那样,它也是一个可以导致的解决方案以 static 初始化顺序惨败的形式出现额外的麻烦。 I'd advise to not do that under almost all circumstances.我建议几乎在所有情况下都不要这样做。

(Plus, a static member also just boils down to the code looking up the same address – so, performance-wise, same as a pointer. Again, nothing really won here.) (另外,一个static成员也归结为查找相同地址的代码——因此,在性能方面,与指针相同。同样,这里没有真正获胜。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM