c++11 - 为什么行为会随着 emplace_back / push_back 顺序的变化而变化?为什么构造函数的数量增加了?
问题描述
class Buffer
{
unsigned char* ptr{nullptr};
size_t length{0};
public:
Buffer() :
ptr(nullptr),
length(0)
{std::cout<<"\n In Buffer()\n";}
explicit Buffer(size_t const size):
ptr(new unsigned char[size] {0}),
length (size)
{std::cout<<"\n In explicit Buffer(size_t const size)\n";}
~Buffer()
{
if (nullptr != ptr) delete [] ptr;
}
// Causing runtime nullptr exception
// Buffer(Buffer const& obj) :
// ptr(new unsigned char[obj.length] {0}),
// length (obj.getLength())
// { std::cout<<"\n In Buffer(Buffer const& obj)\n";}
// Unnessary Fixed Copy Constructor
Buffer(Buffer const& obj) noexcept
{
std::cout<<"\n In Buffer(Buffer const& obj)\n";
std::cout<<"\n obj Details : Length = "<<obj.getLength()<<std::boolalpha<<": (ptr == nullptr) = "<<(nullptr == obj.getPtr())<<"\n";
if (obj.length == 0)
ptr = nullptr;
else
ptr = new unsigned char[obj.length] {0};
length = obj.length;
}
Buffer& operator=(Buffer const obj)
{
std::cout<<"\n In Buffer& operator=(Buffer const obj)\n";
if (this == &obj) return *this;
delete [] this->ptr;
this->ptr = new unsigned char[obj.length]{0};
this->length = obj.length;
return *this;
}
Buffer(Buffer && data)
{
std::cout<<"\n In Buffer(Buffer && data)\n";
std::cout<<"\n obj Details : Length = "<<data.getLength()<<std::boolalpha<<": (ptr == nullptr) = "<<(nullptr == data.getPtr())<<"\n";
ptr = data.ptr;
length = data.length;
data.ptr = nullptr;
data.length = 0;
}
Buffer& operator=(Buffer&& data)
{
std::cout<<"\n In Buffer& operator=(Buffer&& data)\n";
if (this == &data) return *this;
this->ptr = data.ptr;
this->length = data.length;
data.ptr = nullptr;
data.length = 0;
return *this;
}
size_t getLength() const {return length;}
unsigned char* getPtr() const {return ptr;}
};
---------驱动程序代码------
std::vector<Buffer> v;
std::cout<<"\nemplace_back()\n";
v.emplace_back();
std::cout<<"\npush_back(Buffer(2))\n";
v.push_back(Buffer(2));
--------- 使用 By Book Copy 构造函数输出---------
emplace_back()
在缓冲区()
push_back(缓冲区(2))
在显式缓冲区中(size_t const size)
在缓冲区(缓冲区 && 数据)
obj 详细信息:长度 = 2: (ptr == nullptr) = false libc++abi.dylib:以未捕获的 std::bad_alloc 类型异常终止:std::bad_alloc
---------复制构造函数中带有不必要修复的输出---------
emplace_back()
在缓冲区()
push_back(缓冲区(2))
在显式缓冲区中(size_t const size)
在缓冲区(缓冲区 && 数据)
obj 详细信息:长度 = 2: (ptr == nullptr) = false
在缓冲区中(缓冲区常量& obj)
obj详细信息:长度= 0:(ptr == nullptr)= true程序以退出代码结束:0
---------驱动程序代码------
std::vector<Buffer> v;
std::cout<<"\npush_back(Buffer(2))\n";
v.push_back(Buffer(2));
std::cout<<"\nemplace_back()\n";
v.emplace_back();
--------- 使用 By Book Copy 构造函数输出---------
push_back(缓冲区(2))
在显式缓冲区中(size_t const size)
在缓冲区(缓冲区 && 数据)
obj 详细信息:长度 = 2: (ptr == nullptr) = false
emplace_back()
在缓冲区()
In Buffer(Buffer const& obj) 程序以退出代码结束:0
---------复制构造函数中带有不必要修复的输出---------
push_back(缓冲区(2))
在显式缓冲区中(size_t const size)
在缓冲区(缓冲区 && 数据)
obj 详细信息:长度 = 2: (ptr == nullptr) = false
emplace_back()
在缓冲区()
在缓冲区中(缓冲区常量& obj)
obj 详细信息:长度 = 2: (ptr == nullptr) = false
程序以退出代码结束:0
解决方案
new unsigned char[obj.length] {0}
时表现出未定义的行为obj.length == 0
。
[expr.new]/7 noptr-new-declarator中的表达式在以下情况下是错误的: (7.4) — new-initializer是一个花括号初始化列表,并且为其提供初始化器的数组元素的数量...超过要初始化的元素数量。
这里的“表达式”是指方括号内的数组大小。
触发此未定义行为的复制构造函数vector
在需要将其存储从 1 个元素重新分配到 2 个元素时被调用。这就是为什么当您首先推送零大小的缓冲区,然后是非零大小的缓冲区(因此复制零大小的缓冲区)时出现问题,但反之则不然。
您可能想要标记您的移动构造函数noexcept
,然后向量将在重新分配时使用它来代替复制构造函数。
推荐阅读
- excel - 按 Excel 字母数字排序
- c# - 在 Unity 中以随机方向旋转然后移动对象
- python - 如何将 pandas 数据框转换为 geopandas 数据框?
- javascript - API 请求:设置枚举值的更好方法
- javascript - 使用 Python 实现身份验证时出现反应类型错误
- ibm-watson - 请如何在 muy 网站上传 watson 聊天机器人
- php - 我无法回显包含值的 JSON 编码对象
- node.js - 节点 msssql 本地服务器登录失败
- javascript - 如何使用 Express 路由器通过 index.js 查找函数(GET、POST、...)?
- reactjs - 无法在 Jest 中测试反应原生组件