2024-02-04 混用 C 与 C++ 的 calloc 和 new 导致的问题
点击 <C 语言编程核心突破> 快速C语言入门
混用 C 与 C++ 的 calloc 和 new 导致的问题
- 前言
- 一、问题代码
- 二、使用new
- 总结
前言
要解决问题: 同样的代码, 含有std::string
的结构, 在gcc
环境通过calloc
可以赋值, 但是在VS
下不行
想到的思路: std::string
不是平凡类, 按道理不能通过calloc
初始化, 会产生问题, 但神奇的gcc
却貌似可以正常运行.
其它的补充: 混用C
和C++
真的不是一个好的习惯, 尤其涉及内存分配问题.
一、问题代码
#include <cstdlib>
#include <iostream>
#include <string>
#define MAX_PERSON_COUNT 3
struct Person
{
std::string m_name;
int age;
};
int main()
{
std::string name;
std::cin >> name;
Person *test =
static_cast<Person *>(calloc(MAX_PERSON_COUNT, sizeof(Person)));
test->m_name = name;
std::cout << test->m_name;
return 0;
}
在struct Person
中有一个std::string
, 在C++
中, 这是一个需要初始化的元素, 但是calloc
不能调用构造函数, 只会分配一块内存, 且内存中的数据都是0.
然而神奇的是, 在gcc
环境下, 可以给没有初始化的string
赋值,
我们简单分析一下, 如果string
的构造是一个指向字符串的指针, 以及一个代表字符长度的整型值,
那么在进行赋值的时候, 会重新开辟一块内存, 并将其地址传递给string
内部的指针, 并将字符串拷贝过去
同时, 记录长度的值也传递给字符串的记录长度值的成员变量.
但为了保证性能, 可能string
在初始化时默认分配一个足够大的空间, 处理小字符串,
如果在赋值时, 长度未超过这个范围, 直接拷贝字符串到内存中,
那此时calloc
不能初始化的string
在赋值时, 就有了隐患.
而我们不能保证string
的具体实现, 所以, 用calloc
分配带有非平凡类的string
也就不能保证是否可用.
二、使用new
#include <cstdlib>
#include <iostream>
#include <string>
#define MAX_PERSON_COUNT 3
struct Person
{
std::string m_name;
int age;
};
int main()
{
std::string name;
std::cin >> name;
Person *test = new Person[MAX_PERSON_COUNT];
// static_cast<Person *>(calloc(MAX_PERSON_COUNT, sizeof(Person)));
test->m_name = name;
std::cout << test->m_name;
return 0;
}
用new
就意味着, 在C++
中, 编译器会将结构当作类来处理, 使用默认构造函数, 那么string
会被正确初始化, 无论它是如何实现的, 在任何编译器将可正确运行.
总结
混用C
和C++
并不是一个好的习惯, 同时, 这是两种语言, 虽然绝大部分是兼容的, 但我相信, 绝大部分人无法区分, 在任意编译器下, 它们的区分究竟是什么, 这里坑恐怕不少, 如果你有试错的本钱, 可随意, 但如果没有, 还是让上帝的归上帝, 凯撒的归凯撒吧.
点击 <C 语言编程核心突破> 快速C语言入门