int FunctionName(const char *pValueName, const char *pValueData, long iMaxValueSize)
{
char *pDataToStore = const_cast<char *>(pValueData);
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize);
...
...
}
在上面的代码片段中,ProcessData()函数修改它作为参数接收的char *。现在,即使在将pValueData分配到pDataToStore之后,在执行ProcessData()之后,pValueData的值也与pDataToStore相同。
我的目标是保持pValueData的完整值,该值作为const char *
传递答案 0 :(得分:2)
我的目标是保持传递的pValueData的完整值 const char *
这是不可能的。通过const
传递意味着它不能被修改,除非它最初不是常数。
示例:
char *ptr1 = new char[100]; // not const
char *ptr2 = new char[100]; // not const
int i = FunctionName(ptr1, ptr2, 123);
在这种情况下,您可以在技术上保留const_cast
。但是为了什么?只需更改您的函数参数即可char *
:
int FunctionName(char *pValueName, char *pValueData, long iMaxValueSize)
{
int iActualSiz = ProcessData(pValueData, iMaxValueSize);
// ...
}
但是,您很可能希望能够传递常量字符串。例如字符串文字:
int i = FunctionName("name", "data", 123);
字符串文字是不可修改的,因此需要您的函数取char const *
。稍后尝试修改它们会导致未定义的行为。
如您所见,错误在于通用架构和代码逻辑。 您想要修改某些内容,同时又不想允许修改它。
问题是:pDataToStore
完成ProcessData
后会发生什么? FunctionName
的来电者是否需要了解修改?或者它只是FunctionName
的内部业务?
如果它只是FunctionName
的内部业务,那么您可以保持其签名不变,并ProcessData
修改传递数据的副本。这是一个简化(不是异常安全,没有错误检查)示例:
int FunctionName(const char *pValueName, const char *pValueData, long iMaxValueSize)
{
char *copy = new char[strlen(pValueData) + 1];
strcpy(copy, pValueData):
int iActualSiz = ProcessData(copy, iMaxValueSize);
// ...
delete[] copy;
}
好消息是,您现在可以通过隐藏所有低级指针业务来大规模改进FunctionName
的接口。事实上,当C ++标准类可以为你完成所有工作时,为什么要使用这么多指针呢?
int FunctionName(std::string const &valueName, std::string const &valueData, long maxValueSize)
{
std::vector<char> copy(valueData.begin(), valueData.end());
int actualSize = ProcessData(©[0], maxValueSize);
// ...
// no more delete[] needed here
}
std::vector<char>
会自动分配足够的内存来保存valueData
的副本,然后执行复制。即使抛出异常,它也会在不再需要时完全自动释放内存。并且©[0]
(在C ++ 11中可以写为copy.data()
)保证产生指向内部使用数据的指针,因此低级C函数可以修改向量。元件。
(我也有机会删除微软风格的匈牙利表示法。这是90年代失败的实验,你甚至错误地使用它,假设一个前导i
应该表示int
。)
最重要的是:
如果您需要在代码中使用const_cast
进行编译,那么其他地方至少会有一个const
缺失< / em>或一个太多。 A const_cast
总是弥补另一段代码中的错误。它始终是一种解决方法,从来没有预先设计好的解决方案。
答案 1 :(得分:0)
我已经通过创建堆内存解决了这个问题。
char *pDataToStore = new char[iMaxValueSize];
memcpy(pDataToStore, pValueData, iMaxValueSize*sizeof(char));
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize);
...
....
delete []pDataToStore;
答案 2 :(得分:0)
您必须在 const限定类型 和 const限定对象 之间做出改变。
7.1.6.1:cv-qualifiers 部分中的标准状态:( cv = const或volatile)
指向cv限定类型的指针或引用实际上不需要指向 或者引用一个符合cv标准的对象,但它被视为它;一个 const限定访问路径即使不能用于修改对象 引用的对象是非const对象,可以修改 通过其他一些访问途径。
如果你的指针指向一个非const对象,那么cast away将使你能够修改objet,但正如有人告诉你的那样,你正在向你的函数用户撒谎。
你的指针指向一个真正的const对象(即在const保护的内存中),编译器将编译你的代码,但你可能有一个段错误,典型的未定义行为。
这是一个例子,使用“普通字符串文字(...)具有类型”n const char“数组的事实,其中n是字符串的大小(...)”(见标准,第2.14.5节):
char *my_realconst = "This is a real constant string"; // pointer does not claim that it points to const object
(*my_realconst)++; // Try to increment the first letter, will compile but will not run properly !!
因此,如果您的函数ProcessData()是只读取数据但遗忘了参数列表中的const的遗留代码,那么您的抛弃将起作用。但是,如果您的功能正在改变数据,它可能会起作用,也可能会失败,具体取决于创建的数据的创建方式!
因此,如果你不是100%确定效果会是什么,请尽量避免使用const!更好地克隆您的对象,创建临时对象并复制内容。
答案 3 :(得分:0)
我建议你一个小模板来轻松处理这类问题:
template <typename T>
class Buffer {
size_t sz; // size
T* addr; // pointed
public:
Buffer(const T*source, size_t l) : sz(l), addr(new T[l]) { std::copy(source, source + l, addr); } // allocate and copy
~Buffer() { delete[]addr; } // destroy memory
operator T* () { return addr; } // convert to pointer
};
您可以按原样使用现有代码:
Buffer<char> pDataToStore(pValueData, iMaxValueSize); // create the automatic buffer
int iActualSiz = ProcessData(pDataToStore, iMaxValueSize); // automatic use of pointer to buffer
cout << "modified copy: " << pDataToStore << endl;
cout << "original: " << pValueData << endl;
一旦pDataToStore不再在范围内,缓冲区将自动释放。
如果您对wchar_t
缓冲区或其他任何内容有类似问题,它也可以正常工作。
关于抛弃const的邪恶的解释,请参阅我的其他答案