PVS工作室发现了我正在调查的潜在缺陷;警告V623 http://www.viva64.com/en/d/0240/
然而,解释不足以理解临时副本的原因。如果CString :: operator wchar_t *()定义如下:
wchar_t* newbuf = new wchar_t[20];
// do things to put the current CString value in there
return newbuf;
然后是内存泄漏,但没有指向被破坏的临时内容的指针。我只看到另一个可能的实现,即返回CString中包含的已存在的wchar_t *指针,这不会成为新的临时指针。像这样:
return m_pContents;
所以,两个问题;我在哪里可以找到CString的实际实现?而且,这个函数的有效实现(在任何自制类型上)可以让转换运算符返回指向被破坏的临时函数的指针吗?我只是不相信Microsfoot会像以下那样实现它:
CString tempCopy(*this);
return tempCopy.m_pContents;
答案 0 :(得分:1)
以下是CString::operator LPCTSTR
的{{3}}。 LPCTSTR
是const char*
或const wchar_t*
的精美微软名称,具体取决于是否定义了_UNICODE
。
以下是描述:
返回值
指向字符串数据的字符指针。
说明
这个有用的转换运算符提供了一种有效的方法来访问CString对象中包含的以null结尾的C字符串。没有复制字符;只返回一个指针。小心这个操作员。如果在获取字符指针后更改了CString对象,则可能会导致重新分配使指针无效的内存。
所以,让我们继续你的问题。
在哪里可以找到CString的实际实现?
您可以在Microsofts c ++运行时库的源文件中找到它。除非您在Microsoft工作,否则您可能无法访问。
我只是不相信Microsfoot会像以下那样实现它:
CString tempCopy(*this);
return tempCopy.m_pContents;
我也不相信。那将是复制,文档明确指出没有复制。
现在标题中的问题:
为什么将CString转换为wchar_t *会产生临时副本?
没有。好吧,它确实创建了一个指针的副本,但它不会创建包含该字符串的数组的副本。
你误解了这篇文章。以下是代码中断代码的示例:
CString s1(L"1");
wchar_t s2[] = L"2";
bool a = false;
const wchar_t *s = a ? s1 : s2;
临时CString
由s2
构成。 ?:
运算符结束后,该临时值不存在。使用指针并没有错,因为它是由CString::operator wchar_t*()
返回的。使用指针是错误的,因为在临时对象上调用了CString::operator wchar_t*()
。临时CString
不是由CString::operator wchar_t*()
创建的。它是从s2
隐式创建的,因为s1
的类型为CString
。
编辑。你在评论中问道:
那你是怎么知道的? s1:s2返回CString?
我知道无论布尔表达式如何,条件运算符都必须返回相同的类型。我知道如果表达式返回不同的类型,并且一个类型可以隐式转换为另一个类型,那么运算符的返回类型将是另一种类型。我知道wchar_t*
可转换为CString
。因此,条件运算符将返回CString
。
好吧,它可以返回CString
,除了...... CString
也可以转换为wchar_t*
,所以条件运算符可以返回wchar_t*
或CString
,如果确实返回CString
,则最终会有一个悬空指针。您无法对其返回的内容做出假设,因为标准都不能保证。事实上,这使得程序格式不正确,这是示例代码被打破的另一种方式。以下是标准的引用:
[expr.cond]§5.16/ 3(N3797草案)
...确定是否可以转换第二个操作数以匹配第三个操作数,以及是否可以转换第三个操作数以匹配第二个操作数。如果两者都可以转换,或者可以转换,但转换不明确,则程序格式不正确。
答案 1 :(得分:1)
在您关联的PVS工作室代码中,您有一个三元运算符,其中包含wchar_t *
和CString
。您的问题不在于转换运算符,而是三元组正在将wchar_t *
提升为CString
。您需要将结果分配给新的CString
或确保三元参数都是相同的类型,以便您获得引用。
答案 2 :(得分:0)
“有效”(大空中报价)实施可能与
相符class CString {
wchar_t *data_;
size_t max_size_;
size_t size_;
CString() : data_(new wchar_t[20]), max_data_(20), size_(0) {}
//various operations on CString which might or might not do things like
void extend(size_t new_size)
{
wchar_t *old_data = data_;
data_ = new wchar_t[new_size];
memcpy(data_, old_data_, size_);
delete [] old_data;
max_size_ = new_size;
}
//or even
void append(wchar_t c)
{
data_[size_++] = c;
}
operator LPCSTR () const { data_[size_ + 1] = 0; return data_; }
};
因此,如果使用强制转换运算符,则会得到一个指向空终止字符串的指针。直到您(比如说)向字符串添加字符为止。然后指针将指向一个非空终止字符串。或者,如果您在字符串中添加了大量字符,它可以释放内存并将其指向其他位置。在这种情况下,指针指向可能看起来有效的内容,直到下一次内存分配发生并抓取最近释放的内存。