为什么将CString转换为wchar_t *会产生临时副本?如果我们使用其他类型而不是CString怎么办?

时间:2015-10-23 11:56:47

标签: c++ undefined-behavior c-strings temporary

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;

3 个答案:

答案 0 :(得分:1)

以下是CString::operator LPCTSTR的{​​{3}}。 LPCTSTRconst 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;

临时CStrings2构成。 ?:运算符结束后,该临时值不存在。使用指针并没有错,因为它是由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_; }
};

因此,如果使用强制转换运算符,则会得到一个指向空终止字符串的指针。直到您(比如说)向字符串添加字符为止​​。然后指针将指向一个非空终止字符串。或者,如果您在字符串中添加了大量字符,它可以释放内存并将其指向其他位置。在这种情况下,指针指向可能看起来有效的内容,直到下一次内存分配发生并抓取最近释放的内存。