如何在const和非const上下文中使用相同的POD?

时间:2016-03-08 14:27:08

标签: c++ const

最初的问题是我有一些数据可以从板块中保存和检索,并希望以下列方式使用辅助结构:

// this is how I want to use my struct for saving
void safeData()
{
  Data data;
  data.name = getNameToSave(); // returns const char*
  save(data);
}

// ... and in the same way for writing.
void readData()
{
  Data data;
  read(data);
  use(data);
}

......而

struct Data
{
  const char* name;

  // potentially many more data members
}

我现在绑定到(const)char *而不是std :: string,因为这应该与遗留代码一起使用。不幸的是,这会带来一个常量问题:

void read(Data& data)
{
  // initial legacy free
  free(data.name); // warning: can't convert from const char* to void*

  // fill with some data
  data.name = getNameFromPlate();
}

所以事情是这样的:因为我的读取数据检索方法如getNameFromSomewhere返回const char *我必须使我的struct成员也成为const。然而,这与写入使用冲突,因为在这种情况下它们必须是非const的。解决这个问题的最佳和最干净的方法是什么?

2 个答案:

答案 0 :(得分:0)

最简洁的方法是Data结构拥有 name数据。所以当你分配它时你应该分配内存并做一个memcpy。这是确保a)不泄漏内存的唯一方法b)在完成数据之前不释放数据c)同时其他进程不会更改数据。

由于您无论如何都要复制,因此可以使用std :: string而不是const char*来使其更易于管理。当您为const char*分配时,std :: string将为您执行复制,您可以使用const char*获得c_str(),这样您仍然可以使用旧版架构。您无需进行切换,但从长远来看,这样可以更轻松地进行管理。

答案 1 :(得分:0)

您不仅存在常量问题,还存在所有权问题。除非API声明调用者在使用后必须释放getNameToSave()的返回值,否则您应该释放它。当您从文件中读取文件时,必须将其释放。

因此,更简单的方法是始终使用您在使用后始终免费使用的本地副本。由于您需要使用旧的const char *代替std::string,因此您最好继续使用旧的C库函数。这里最好的函数是strdup,它自动分配内存并将旧字符串复制到其中。

另一种方法是将成员Data::name的状态存储在布尔成员中:

struct Data
{
  const char* name;
  bool dyn; // must be freed if true

  // potentially many more data members
}

然后您可以安全地使用:

if (data.dyn && (data.name != nullptr)) {
    free(const_cast<char *>(data.name);
}