点击 <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 3struct 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 3struct 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语言入门