vector<bool>STL中的陷阱

C++的vector<bool>在STL中有一个特殊的实现,它利用位操作节省空间,但这也导致了一些问题。由于vector<bool>使用代理对象而非实际的bool数组,取地址操作可能会失败,导致编译错误。为避免此类问题,建议在需要布尔数组时使用unsigned char代替。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天 ,写代码的时候我想用一个数组把布尔值存起来,就像这样: 

vector<bool> a;
	if (isOrder(num)) {
		a.push_back(true);
	}
然后取他的一个元素的地址时:

bool* ptr = &a[0];
就出现了编译错误:

error C2440: “初始化”: 无法从“std::_Vb_reference<std::_Wrap_alloc<std::allocator<_Other>>> *”转换为“bool *”

note: 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换

什么意思呢?

我查阅了文档,了解到在容器里C++标准对于vecotr<bool>值有其特殊的实现方法。目的是为了减小空间的耗用。一个bool值的存储其实只用了1位,也就是说要八个bool值才刚好是一个字节。而且由于vector<bool>逐位进行存取访问,所以访问速度通常比int之类的普通类型操作要慢很多。那么为什么其实如果不取地址的话话说可以编译成功的,那么为什么取地址以后就失败了呢?

我查阅到了这样一段话:


是的他是通过一种叫代理对象(proxy object)的方法来实现的,他不是一个标准容器,只是一个近似于容器的存在。

所以对于这种情况,我们应该尽量避免其发生,特别是算法中会否有对vecotr地址进行解引用操作的可能。

我们不建议这样使用vector,而应该使用unsigned char这样来代替。


#include <graphics.h> // EasyX图形库 #include <fstream> #include <string> #include <vector> #include <iomanip> #include <algorithm> using namespace std;; // 全局常量定义 const int WIDTH = 800; // 窗口宽度 const int HEIGHT = 600; // 窗口高度 const int MARGIN = 20; // 边距 const int BUTTON_HEIGHT = 40;// 按钮高度 const int INPUT_HEIGHT = 30; // 输入框高度 class InputBox; // 用户信息结构 class User { public: string nickname; string account; string password; int levelsCleared; }; // 按钮类,用于封装界面按钮 class Button { private: int x, y, width, height; string text; bool isHovered; COLORREF normalColor, hoverColor, textColor; public: Button(int _x, int _y, int _width, int _height, string _text) : x(_x), y(_y), width(_width), height(_height), text(_text), isHovered(false) { normalColor = RGB(200, 200, 200); hoverColor = RGB(150, 150, 150); textColor = RGB(0, 0, 0); } // 绘制按钮 void draw() { setfillcolor(isHovered ? hoverColor : normalColor); fillrectangle(x, y, x + width, y + height); settextcolor(textColor); settextstyle(20, 0, _T("宋体")); int textWidth = textwidth(text.c_str()); int textHeight = textheight(text.c_str()); outtextxy(x + (width - textWidth) / 2, y + (height - textHeight) / 2, text.c_str()); } // 检查鼠标是否在按钮上 bool isMouseOver(int mx, int my) { return mx >= x && mx <= x + width && my >= y && my <= y + height; } // 设置鼠标悬停状态 void setHovered(bool hover) { isHovered = hover; } string getText() const { return text; } }; // 输入框类 class InputBox { private: int x, y, width, height; string text; string placeholder; bool isFocused; COLORREF bgColor, borderColor, textColor, placeholderColor; public: InputBox(int _x, int _y, int _width, int _height, string _placeholder) : x(_x), y(_y), width(_width), height(_height), placeholder(_placeholder), isFocused(false) { bgColor = RGB(255, 255, 255); borderColor = RGB(150, 150, 150); textColor = RGB(0, 0, 0); placeholderColor = RGB(180, 180, 180); } // 绘制输入框 void draw() { // 绘制背景和边框 setfillcolor(bgColor); fillrectangle(x, y, x + width, y + height); setlinecolor(borderColor); rectangle(x, y, x + width, y + height); // 绘制文本或占位符 settextcolor(isFocused || !text.empty() ? textColor : placeholderColor); settextstyle(16, 0, _T("宋体")); if (text.empty() && !isFocused) { outtextxy(x + 5, y + (height - textheight(placeholder.c_str())) / 2, placeholder.c_str()); } else { outtextxy(x + 5, y + (height - textheight(text.c_str())) / 2, text.c_str()); } // 绘制光标 if (isFocused) { int cursorX = x + 5 + textwidth(text.c_str()); int cursorY = y + 5; int cursorHeight = height - 10; solidrectangle(cursorX, cursorY, cursorX + 2, cursorY + cursorHeight); } } // 处理键盘输入 void handleKey(int key) { if (!isFocused) return; if (key == VK_BACK) { // 退格键 if (!text.empty()) text.pop_back(); } else if (key == VK_RETURN) { // 回车键 isFocused = false; } else if (key >= 32 && key <= 126) { // 可打印字符 text += (char)key; } } // 设置焦点 void setFocus(bool focus) { isFocused = focus; } // 获取输入文本 string getText() const { return text; } // 清空输入文本 void clear() { text = ""; } bool isMouseOver(int mx, int my) const { return (mx >= x && mx <= x + width && my >= y && my <= y + height); } }; // 读取所有用户信息 vector<User> readUsers() { vector<User> users; ifstream file("users.txt"); if (file.is_open()) { string line; // 跳过标题行 if (getline(file, line)) { while (getline(file, line)) { User user; size_t pos1 = line.find('\t'); size_t pos2 = line.find('\t', pos1 + 1); size_t pos3 = line.find('\t', pos2 + 1); if (pos1 != string::npos && pos2 != string::npos && pos3 != string::npos) { user.nickname = line.substr(0, pos1); user.account = line.substr(pos1 + 1, pos2 - pos1 - 1); user.password = line.substr(pos2 + 1, pos3 - pos2 - 1); user.levelsCleared = stoi(line.substr(pos3 + 1)); users.push_back(user); } } } file.close(); } return users; } // 保存用户信息到文件 bool saveUsers(const vector<User>& users) { ofstream file("users.txt"); if (!file.is_open()) { return false; } // 写入标题行 file << "nickname\taccount\tpassword\tlevelsCleared" << endl; // 写入所有用户 for (const auto& user : users) { file << user.nickname << "\t" << user.account << "\t" << user.password << "\t" << user.levelsCleared << endl; } file.close(); return true; } // 主窗口类 class MainWindow { private: vector<Button> buttons; vector<InputBox> inputBoxes; vector<User> users; int currentPage; bool isAddingUser; string currentAccount; public: MainWindow() : currentPage(0), isAddingUser(false) { // 初始化图形窗口 initgraph(WIDTH, HEIGHT); setbkcolor(RGB(240, 240, 240)); cleardevice(); // 确保文件存在并写入标题行 ifstream checkFile("users.txt"); if (!checkFile.good()) { ofstream createFile("users.txt"); if (createFile.is_open()) { createFile << "nickname\taccount\tpassword\tlevelsCleared" << endl; createFile.close(); } } checkFile.close(); // 初始化界面元素 initUI(); } ~MainWindow() { closegraph(); } // 初始化用户界面 void initUI() { buttons.clear(); inputBoxes.clear(); if (isAddingUser) { // 添加用户界面 initAddUserUI(); } else { // 主菜单界面 initMainMenuUI(); } } // 初始化主菜单界面 void initMainMenuUI() { // 标题 settextcolor(RGB(50, 50, 200)); settextstyle(30, 0, _T("宋体")); outtextxy((WIDTH - textwidth(_T("用户信息管理系统"))) / 2, 50, _T("用户信息管理系统")); // 按钮 int buttonWidth = 200; int yPos = 150; buttons.push_back(Button((WIDTH - buttonWidth) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "添加用户信息")); yPos += 80; buttons.push_back(Button((WIDTH - buttonWidth) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "查看所有用户")); yPos += 80; buttons.push_back(Button((WIDTH - buttonWidth) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "修改用户信息")); yPos += 80; buttons.push_back(Button((WIDTH - buttonWidth) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "删除用户信息")); yPos += 80; buttons.push_back(Button((WIDTH - buttonWidth) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "退出系统")); } // 初始化添加用户界面 void initAddUserUI() { // 标题 settextcolor(RGB(50, 50, 200)); settextstyle(24, 0, _T("宋体")); outtextxy((WIDTH - textwidth(_T("添加用户信息"))) / 2, 30, _T("添加用户信息")); // 输入框 int inputWidth = 300; char buffer[32]; _itoa_s((WIDTH - inputWidth) / 2, buffer, 10); int yPos = 100; inputBoxes.push_back(InputBox(buffer, yPos, _T("inputWidth"), _T("INPUT_HEIGHT"), "请输入昵称")); yPos += 60; inputBoxes.push_back(InputBox(buffer, yPos, _T("inputWidth"), _T("INPUT_HEIGHT"), "请输入账号")); yPos += 60; inputBoxes.push_back(InputBox(buffer, yPos, _T("inputWidth"), _T("INPUT_HEIGHT"), "请输入密码")); yPos += 60; inputBoxes.push_back(InputBox(buffer, yPos, _T("inputWidth"), _T("INPUT_HEIGHT"), "请输入通关数")); // 按钮 int buttonWidth = 120; yPos += 80; buttons.push_back(Button((WIDTH - buttonWidth * 2 - 20) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "确认添加")); buttons.push_back(Button((WIDTH + buttonWidth * 2 + 20) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "取消")); } // 绘制用户列表界面 void drawUserList() { cleardevice(); // 标题 settextcolor(RGB(50, 50, 200)); settextstyle(24, 0, _T("宋体")); outtextxy((WIDTH - textwidth(_T("用户信息列表"))) / 2, 30, _T("用户信息列表")); // 读取用户数据 users = readUsers(); if (users.empty()) { settextcolor(RGB(0, 0, 0)); settextstyle(18, 0, _T("宋体")); outtextxy((WIDTH - textwidth(_T("暂无用户信息"))) / 2, 100, _T("暂无用户信息")); // 返回按钮 int buttonWidth = 120; buttons.clear(); buttons.push_back(Button((WIDTH - buttonWidth) / 2, 180, buttonWidth, BUTTON_HEIGHT, "返回主菜单")); return; } // 绘制表头 settextcolor(RGB(0, 0, 0)); settextstyle(16, 0, _T("宋体")); outtextxy(MARGIN, 80, _T("昵称")); outtextxy(MARGIN + 120, 80, _T("账号")); outtextxy(MARGIN + 240, 80, _T("密码")); outtextxy(MARGIN + 360, 80, _T("通关数")); line(MARGIN, 100, WIDTH - MARGIN, 100); // 绘制用户数据 int yPos = 120; for (size_t i = 0; i < users.size(); i++) { if (yPos > HEIGHT - 100) break; outtextxy(MARGIN, yPos, users[i].nickname.c_str()); outtextxy(MARGIN + 120, yPos, users[i].account.c_str()); outtextxy(MARGIN + 240, yPos, users[i].password.c_str()); outtextxy(MARGIN + 360, yPos, to_string(users[i].levelsCleared).c_str()); yPos += 30; } // 按钮 int buttonWidth = 120; buttons.clear(); buttons.push_back(Button(MARGIN, HEIGHT - 80, buttonWidth, BUTTON_HEIGHT, "返回主菜单")); } // 处理修改用户界面 void processModifyUser() { cleardevice(); // 标题 settextcolor(RGB(50, 50, 200)); settextstyle(24, 0, _T("宋体")); outtextxy((WIDTH - textwidth(_T("修改用户信息"))) / 2, 30, _T("修改用户信息")); // 输入框 - 账号 int inputWidth = 300; char buffer[32]; _itoa_s((WIDTH - inputWidth) / 2, buffer, 10); inputBoxes.clear(); inputBoxes.push_back(InputBox(buffer, 100, "inputWidth", "INPUT_HEIGHT", "请输入要修改的用户账号")); // 按钮 int buttonWidth = 120; buttons.clear(); buttons.push_back(Button((WIDTH - buttonWidth) / 2, 180, buttonWidth, BUTTON_HEIGHT, "查找用户")); buttons.push_back(Button((WIDTH - buttonWidth) / 2, 240, buttonWidth, BUTTON_HEIGHT, "返回主菜单")); } // 显示用户修改界面 void showModifyUserInterface(const string& account) { cleardevice(); // 查找用户 users = readUsers(); User* userToModify = nullptr; for (auto& user : users) { if (user.account == account) { userToModify = &user; break; } } if (!userToModify) { settextcolor(RGB(200, 0, 0)); settextstyle(18, 0, _T("宋体")); outtextxy((WIDTH - textwidth(_T("未找到该用户!"))) / 2, 100, _T("未找到该用户!")); // 返回按钮 int buttonWidth = 120; buttons.clear(); buttons.push_back(Button((WIDTH - buttonWidth) / 2, 180, buttonWidth, BUTTON_HEIGHT, "返回主菜单")); return; } // 标题 settextcolor(RGB(50, 50, 200)); settextstyle(24, 0, _T("宋体")); outtextxy((WIDTH - textwidth(_T("修改用户信息"))) / 2, 30, _T("修改用户信息")); // 显示当前信息 settextcolor(RGB(0, 0, 0)); settextstyle(16, 0, _T("宋体")); outtextxy(MARGIN, 80, _T("当前用户信息:")); outtextxy(MARGIN, 110, ("昵称: " + userToModify->nickname).c_str()); outtextxy(MARGIN, 140, ("账号: " + userToModify->account).c_str()); outtextxy(MARGIN, 170, ("密码: " + userToModify->password).c_str()); outtextxy(MARGIN, 200, ("通关数: " + to_string(userToModify->levelsCleared)).c_str()); // 输入框 int inputWidth = 300; char buffer[32]; _itoa_s((WIDTH - inputWidth) / 2, buffer, 10); int yPos = 250; inputBoxes.clear(); inputBoxes.push_back(InputBox(buffer, yPos, _T("inputWidth"), _T("INPUT_HEIGHT"), "新昵称 (留空保持不变)")); yPos += 60; inputBoxes.push_back(InputBox(buffer, yPos, _T("inputWidth"), _T("INPUT_HEIGHT"), "新密码 (留空保持不变)")); yPos += 60; inputBoxes.push_back(InputBox(buffer, yPos, _T("inputWidth"), _T("INPUT_HEIGHT"), "新通关数 (留空保持不变)")); // 保存用户账号 currentAccount = account; // 按钮 int buttonWidth = 120; yPos += 80; buttons.push_back(Button((WIDTH - buttonWidth * 2 - 20) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "确认修改")); buttons.push_back(Button((WIDTH + buttonWidth * 2 + 20) / 2, yPos, buttonWidth, BUTTON_HEIGHT, "取消")); } // 处理删除用户界面 void processDeleteUser() { cleardevice(); // 标题 settextcolor(RGB(50, 50, 200)); settextstyle(24, 0, _T("宋体")); outtextxy((WIDTH - textwidth(_T("删除用户信息"))) / 2, 30, _T("删除用户信息")); // 输入框 - 账号 int inputWidth = 300; char buffer[32]; _itoa_s((WIDTH - inputWidth) / 2, buffer, 10); inputBoxes.clear(); inputBoxes.push_back(InputBox(buffer, 100, "inputWidth", "INPUT_HEIGHT", "请输入要删除的用户账号")); // 按钮 int buttonWidth = 120; buttons.clear(); buttons.push_back(Button((WIDTH - buttonWidth) / 2, 180, buttonWidth, BUTTON_HEIGHT, "确认删除")); buttons.push_back(Button((WIDTH - buttonWidth) / 2, 240, buttonWidth, BUTTON_HEIGHT, "返回主菜单")); } // 运行主循环 void run() { ExMessage msg; // 消息结构 while (true) { cleardevice(); // 根据当前状态绘制界面 if (isAddingUser) { initAddUserUI(); } else { initMainMenuUI(); } // 绘制所有按钮 for (auto& button : buttons) { button.draw(); } // 绘制所有输入框 for (auto& input : inputBoxes) { input.draw(); } // 处理消息 if (peekmessage(&msg, EM_MOUSE | EM_KEY)) { // 鼠标消息 if (msg.message == WM_LBUTTONDOWN) { // 处理按钮点击 bool buttonClicked = false; for (auto& button : buttons) { if (button.isMouseOver(msg.x, msg.y)) { buttonClicked = true; string text = button.getText(); if (text == "添加用户信息") { isAddingUser = true; initUI(); } else if (text == "查看所有用户") { drawUserList(); } else if (text == "修改用户信息") { processModifyUser(); } else if (text == "删除用户信息") { processDeleteUser(); } else if (text == "退出系统") { closegraph(); return; } else if (text == "确认添加") { if (inputBoxes.size() >= 4) { User newUser; newUser.nickname = inputBoxes[0].getText(); newUser.account = inputBoxes[1].getText(); newUser.password = inputBoxes[2].getText(); string levelsText = inputBoxes[3].getText(); newUser.levelsCleared = levelsText.empty() ? 0 : stoi(levelsText); // 保存到文件 ofstream file("users.txt", ios::app); if (file.is_open()) { file << newUser.nickname << "\t" << newUser.account << "\t" << newUser.password << "\t" << newUser.levelsCleared << endl; file.close(); isAddingUser = false; } else { settextcolor(RGB(200, 0, 0)); outtextxy(100, 300, _T("保存失败!")); } } } else if (text == "取消") { isAddingUser = false; initUI(); } else if (text == "查找用户" && inputBoxes.size() > 0) { string account = inputBoxes[0].getText(); if (!account.empty()) { showModifyUserInterface(account); } } else if (text == "确认修改" && !currentAccount.empty() && inputBoxes.size() >= 3) { users = readUsers(); for (auto& user : users) { if (user.account == currentAccount) { string newNickname = inputBoxes[0].getText(); if (!newNickname.empty()) user.nickname = newNickname; string newPassword = inputBoxes[1].getText(); if (!newPassword.empty()) user.password = newPassword; string newLevels = inputBoxes[2].getText(); if (!newLevels.empty()) user.levelsCleared = stoi(newLevels); break; } } saveUsers(users); currentAccount = ""; initMainMenuUI(); } else if (text == "确认删除" && inputBoxes.size() > 0) { string account = inputBoxes[0].getText(); if (!account.empty()) { users = readUsers(); vector<User> newUsers; bool found = false; for (const auto& user : users) { if (user.account == account) { found = true; } else { newUsers.push_back(user); } } if (found) { saveUsers(newUsers); } else { settextcolor(RGB(200, 0, 0)); outtextxy(100, 300, _T("未找到该用户!")); } initMainMenuUI(); } } else if (text == "返回主菜单") { initMainMenuUI(); } break; } } // 处理输入框焦点 if (!buttonClicked) { for (auto& input : inputBoxes) { input.setFocus(input.isMouseOver(msg.x, msg.y)); } } } // 键盘消息 else if (msg.message == WM_KEYDOWN) { for (auto& input : inputBoxes) { input.handleKey(msg.vkcode); } } } FlushBatchDraw(); // 批量绘制,提高性能 Sleep(10); // 短暂休眠,降低CPU占用 } } }; int main() { MainWindow window; window.run(); return 0; }为什么在vector<InputBox> inputBoxes;中显示函数 "InputBox" 不是类型名,InputBox明明声明定义在MainWindow前
06-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值