代码之家  ›  专栏  ›  技术社区  ›  Spring E. Thing

std::vector、std::map、std::string等作为结构成员?

  •  2
  • Spring E. Thing  · 技术社区  · 1 年前

    我很习惯C#,其中 struct 最好只保留的成员 unmanaged 类型,以便 sizeof() 这个 结构 是预先确定的,并且可以完全视为值类型。

    当一个人写下这样的东西时:

    std::vector<T> myVec;

    作为的成员 结构 在C++头文件中,据我所知,这会分配的一个实例 std::vector<T> class 在堆栈上,而不是在哪里 es通常在堆上通过指针进行引用(尽管我在C++中知道 结构 定义比C#中的定义相似得多)。

    我想知道的是使用引用类型的一般记忆含义是什么 std::矢量<T> , std::string , std::map<T,T> 就好像它们是属于堆栈中的值类型一样?最重要的是:

    1. Will my 结构 仍然是固定大小的,如果我使用这些示例类型作为的成员 结构 ?

    2. 使用指向这些类型的指针作为我的成员会更好吗 结构 以便我知道成员在(例如)64位机器上有8个字节大?

    3. 堆栈会分配我的实例吗 结构 像这样设置( structInstA = structInstB )有一些成员是我的各种 std:: 成员,还是它们将是具有相同元素的唯一成员?

    感谢阅读!

    1 回复  |  直到 1 年前
        1
  •  3
  •   ShadowRanger    1 年前
    1. 如果我使用这些示例类型作为结构的成员,我的结构仍然是固定大小的吗?

    在C++中,结构本身是 总是 固定尺寸;一些编译器支持可变长度结构作为扩展,但它不是语言标准的一部分,而且这些类型都不需要它。

    std::vector , std::map , std::string 和company执行动态内存分配,因此结构本身只存储少数指针(例如 vector ,已分配容量指针的开始、结束和结束),并且根据需要从堆中分配任何可变长度的数据。

    1. 我最好使用指向这些类型的指针作为结构的成员,这样我就知道(例如)64位机器上的成员有8个字节大吗?

    不,使用指针只会进一步分割内存。考虑指针的主要原因是如果您想共享 相同的 跨结构的多个实例的容器(例如 std::shared_ptr ),或在特定情况下 std::字符串 ,以允许所有权在不可能失效的情况下转移 std::string_view 底层数据的s(某些实现中使用的小字符串优化意味着字符串数据的迭代器和视图可以通过移动而无效)。

    1. 像这样的结构集(structInstA=structInstB)的堆栈分配实例的成员是我的各种std::成员的浅副本吗?还是它们是具有相同元素的唯一成员?

    如果将它们存储为原始值,而不是指针,则副本(堆栈分配或其他方式)将(通常) 深的 各种收藏的副本。如果你改为使用 std::shared_ptr -如果是集合的包装版本,它将进行极浅的复制(副本将指与原始集合完全相同的集合,但其中任何一个都可以重新分配到集合的新版本以断开连接)。


    附加说明:

    C++结构和类是 完全相同的 ,除了 区别:结构成员默认具有公共可见性,类默认为私有可见性。两者都可以在堆栈上(如果声明为非- static ,非- constexpr 在函数体中,没有 new 或其他分配帮助程序,如 std::make_shared 等等),两者都可以在堆上(具有 / std::make_shared 等或者它们可以在全局内存中(如果在函数外部声明,或者在函数内部声明为 静止的 s

    但在您提到的所有容器类型中,存储在堆栈/堆/全局内存上的位都是微不足道的,只有少数指针。它们包含的所有数据都在堆上,由类本身自动管理。当复制到该类型的新实例时,会分配新的堆内存,复制所有包含的数据(这可能会调用额外的堆分配),然后这两个实例完全不相关(一些复制构造函数可能不会像 shared_ptr s、 但它们是例外,而不是规则)。这就是为什么 std::move 存在;如果你不这样做 需要 两个数据副本,您只想转移数据的所有权(例如,您已经填充了 std::矢量 并想把它交给其他人 struct 从那时起将拥有它), std::移动 减少了从分配和深度复制所有内容(可能非常昂贵)到只复制指针并将源指针归零的成本(通常是六个处理器周期的问题)。