在 C++ 向量中存储指针时出错
Posted
技术标签:
【中文标题】在 C++ 向量中存储指针时出错【英文标题】:Error when storing pointers in c++ vectors 【发布时间】:2020-04-10 17:39:56 【问题描述】:我正在尝试使用 c++ 向量来存储指向如下结构的指针:
struct SourceDir
int id;
const unsigned char *alias;
const unsigned char *description;
const unsigned char *path;
;
但是,我无法检索似乎已损坏的值
std::vector<SourceDir*> source_dirs;
while ((step = sqlite3_step(stmt)) != SQLITE_DONE)
if (step != SQLITE_ROW)
std::cerr << "[ERROR] internal error (SQLite error code" << step << ")\n";
exit(1);
struct SourceDir *sourceDir = new SourceDir;
sourceDir->id = sqlite3_column_int(stmt, 0);
sourceDir->alias = sqlite3_column_text(stmt, 1);
sourceDir->path = sqlite3_column_text(stmt, 2);
sourceDir->description = sqlite3_column_text(stmt, 3);
source_dirs.push_back(sourceDir);
for (std::vector<SourceDir*>::iterator it = source_dirs.begin() ; it != source_dirs.end() ; ++it)
SourceDir *s = *it;
std::cerr << s->description << "\n";
它给出像这样的随机值:
@O?V
@O?V
我不明白我做错了什么
【问题讨论】:
sqlite 函数返回指向与语句句柄关联的内部内存的指针,这些指针很快就会被销毁。您保存的指针最终指向毫无价值的垃圾。关于如何在 C++ 应用程序中管理内存的更多信息和理解,您应该查阅 C++ 教科书。 你为什么不立即获取那些 sqllite 函数的返回值,并从中创建真正的std::string
,而不是在 unsigned char *
中使用 unsigned char *
指针?
谢谢你的建议,我去试试
【参考方案1】:
C 字符串的类型为 char*
或 const char*
。因为它们很常见而且仍然很重要,所以<<
运算符在std::ostream
中有一个额外的重载。 char*
的这种特殊重载会打印取消引用的字符,直到找到空字节。
但是,unsigned char*
是不同的类型,将使用另一个重载。在这里,只需打印指针值。这就是你所看到的。
解决方案:只需将您的字符串成员更改为const char*
。
编辑:这个答案是完全错误的。 unsigned char*
也选择了相同的 C 字符串重载。
【讨论】:
对不起,它没有改变结果..我将结构更改为具有 const char* 成员,然后在将 sqlite3_column_text 调用为 (const char*) 时进行了强制转换,但它仍在打印指针价值观.. 你说得对,我的参考资料已经过时了。 感谢您帮助我!【参考方案2】:指针很好,但它们指向的内存内容可能发生了变化(例如,这里:https://sqlite.org/capi3ref.html#sqlite3_column_blob 你可以读到返回的指针仅在一段时间内有效)。
一般来说,避免在 C++ 中使用原始指针。在这种情况下,您可以只使用 std::string 来复制 sqlite 提供的数据。
比较这段代码,它做了一些小的改动以避免手动内存管理和原始指针:
struct SourceDir
int id;
std::string alias;
std::string description;
std::string path;
;
std::vector<SourceDir> source_dirs;
while ((step = sqlite3_step(stmt)) != SQLITE_DONE)
if (step != SQLITE_ROW)
std::cerr << "[ERROR] internal error (SQLite error code" << step << ")\n";
exit(1);
source_dirs.emplace_back();
auto& sourceDir = source_dirs.back();
sourceDir.id = sqlite3_column_int(stmt, 0);
sourceDir.alias = sqlite3_column_text(stmt, 1);
sourceDir.path = sqlite3_column_text(stmt, 2);
sourceDir.description = sqlite3_column_text(stmt, 3);
for (const auto& s : source_dirs)
std::cerr << s.description << "\n";
【讨论】:
谢谢斯利马克!【参考方案3】:从 sqlite3_column_text 返回的数据归 sqlite3 库所有,仅在那个时刻可用。在读取下一列或下一行之前,我们需要将其保存到我们自己的空间中。 sqlite3 内部的相同数据将用于存储新返回的数据。这是一个示例,您可以尝试解决此问题。
struct SourceDir
int id;
unsigned char *alias;
unsigned char *description;
unsigned char *path;
;
std::vector<SourceDir*> source_dirs;
while ((step = sqlite3_step(stmt)) != SQLITE_DONE)
if (step != SQLITE_ROW)
std::cerr << "[ERROR] internal error (SQLite error code" << step << ")\n";
exit(1);
struct SourceDir *sourceDir = new SourceDir;
sourceDir->id = sqlite3_column_int(stmt, 0);
const unsigned char *col = sqlite3_column_text(stmt, 1);
sourceDir->alias = new unsigned char[strlen(col)+1];
strcpy((char *)sourceDir->alias, col);
col = sqlite3_column_text(stmt, 2);
sourceDir->path = new unsigned char[strlen(col)+1];
strcpy((char *)sourceDir->path, col);
col = sqlite3_column_text(stmt, 3);
sourceDir->description = new unsigned char[strlen(col)+1];
strcpy((char *)sourceDir->description, col);
source_dirs.push_back(sourceDir);
std::vector<SourceDir *>::iterator it = source_dirs.begin();
for (; it != source_dirs.end() ; ++it)
std::cout << (*it)->id << " \"" << (*it)->alias << "\" \""
<< (*it)->path << "\" \"" << (*it)->description
<< "\"\n";
//to clean up
it = source_dirs.begin();
for (; it != source_dirs.end(); it++)
delete [] (*it)->alias;
delete [] (*it)->path;
delete [] (*it)->description;
delete *it;
source_dirs.clear();
【讨论】:
以上是关于在 C++ 向量中存储指针时出错的主要内容,如果未能解决你的问题,请参考以下文章