我很习惯 C#,其中
struct
最好只包含 unmanaged
类型的成员,以便 sizeof()
struct
是预先确定的,并且可以完全视为值类型。
当一个人写下这样的话:
std::vector<T> myVec;
作为 C++ 头文件中
struct
的成员,我的理解是,这会在堆栈上分配 std::vector<T>
class
的实例,而不是 class
通常在要引用的堆上分配通过指针(尽管我知道在 C++ 中 struct
和 class
定义比在 C# 中更相似)。
我想知道的是,使用像
std::vector<T>
、std::string
、std::map<T,T>
这样的引用类型的一般内存含义是什么,就好像它们是像这样属于堆栈的值类型一样?最重要的是:
如果我使用这些示例类型作为
struct
的成员,我的 struct
仍然具有固定大小吗?
我是否最好使用指向这些类型的指针作为我的
struct
的成员,以便我知道该成员在(例如)64位机器上有8个字节大?
我的
struct
集的堆栈分配实例(structInstA = structInstB
)的成员是否是我的各种std::
成员的浅拷贝,或者它们是否是具有相同元素的唯一成员?
感谢您的阅读!
- 如果我使用这些示例类型作为结构体的成员,我的结构体仍然具有固定大小吗?
在 C++ 中,结构体本身始终具有固定大小;某些编译器支持可变长度结构作为扩展,但它不是语言标准的一部分,并且这些类型都不需要它。
std::vector
、std::map
、std::string
和公司执行动态内存分配,因此结构本身仅存储少量指针(例如,对于vector
,分配容量指针的开始、结束和结束),并且根据需要分配任何可变长度数据。
- 我最好使用指向这些类型的指针作为我的结构的成员,以便我知道该成员在(例如)64 位机器上有 8 个字节大吗?
不,使用指针只会进一步破坏你的记忆。考虑指针的主要原因是,如果您想在结构的多个实例之间共享 same 容器(例如,使用
std::shared_ptr
),或者在 std::string
的特定情况下,允许所有权转移而不会潜在地使底层数据的 std::string_view
无效(某些实现中使用的小字符串优化意味着字符串数据的迭代器和视图可以通过移动而无效)。
- 像这样的结构集的堆栈分配实例(structInstA = structInstB)是否具有作为我的各种 std:: 成员的浅拷贝的成员,或者它们是否是具有相同元素的唯一成员?
如果将它们存储为原始值,而不是指针,则副本(堆栈分配或其他方式)将(通常)是各种包含的集合的深副本。如果您使用
std::shared_ptr
包装的集合版本,它将执行非常浅的副本(该副本将引用与原始集合完全相同的集合,但其中任何一个都可以重新分配给该集合的新版本以打破连接)。