为什么将CString类型转换为wchar_t*会产生一个临时副本?如果我们使用其他类型而不是CString呢?
Why does casting a CString to wchar_t* yield a temporary copy? What if we used some other type instead of CString?
PVS studio发现了一个潜在的缺陷,我正在调查;警告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;
则存在内存泄漏,但没有指向已销毁的临时对象的指针。我看到只有一个其他可能的实现,这是返回一个已经存在的wchar_t*指针包含在CString中,这不会使一个新的临时。像这样:
return m_pContents;
两个问题;我在哪里可以找到CString的实际实现?而且,这个函数的什么有效实现(在任何自定义类型上)可以让转换操作符返回一个指向销毁的临时对象的指针?我只是不相信微软会这样实现它:
CString tempCopy(*this);
return tempCopy.m_pContents;
在您链接的pv工作室代码中,您有一个三元运算符取wchar_t *
和CString
。您的问题不在于转换运算符,而是三元将wchar_t *
提升为CString
。您要么需要将结果赋值给新的CString
,要么确保三元参数都是相同的类型,以便获得引用。
以下是CString::operator LPCTSTR
的文档。LPCTSTR
是const char*
或const wchar_t*
的花哨的microsoft名称,取决于是否定义了_UNICODE
。
描述如下:
返回值指向字符串数据的字符指针。
的评论
这个有用的强制转换操作符提供了一种有效的方法来访问CString对象中包含的以空结束的C字符串。没有字符被复制;只返回一个指针。小心这个操作员。如果在获得字符指针后更改CString对象,可能会导致内存重新分配,从而使指针失效。
那么,让我们继续你的问题。
我在哪里可以找到CString的实际实现?
您可以在microsoft c++运行库的源文件中找到它。除非你在微软工作,否则你可能无法访问。
我只是不相信微软会像这样实现它:
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;
从s2
构造临时CString
。在?:
操作符结束后,该临时操作不存在。使用指针并没有错,因为它是由CString::operator wchar_t*()
返回的。使用指针是错误的,因为CString::operator wchar_t*()
是在临时对象上调用的。临时CString
不是由CString::operator wchar_t*()
创建的。它是由s2
隐式创建的,因为s1
的类型是CString
。
编辑。你在评论中问道:
你是怎么知道a的?s1: s2返回一个CString?
我知道无论布尔表达式是什么,条件运算符必须返回相同的类型。我知道,如果表达式返回不同的类型,并且一种类型可以隐式转换为另一种类型,那么操作符的返回类型将是另一种类型。我知道wchar_t*
可以转换为CString
。因此,条件运算符将返回一个CString
。
嗯,它可以返回CString
,除了…CString
也可以转换为wchar_t*
,因此条件运算符可以返回wchar_t*
或CString
,如果它确实返回CString
,那么您最终会得到一个悬垂指针。你不能对它的回报做出假设,因为这两者都没有得到标准的保证。事实上,这使得程序形式不良,这是示例代码被破坏的另一种方式。以下是标准中的一段话:
[expr。§5.16/3(草案N3797)
…确定第二个操作数是否可以转换为匹配第三个操作数,以及第三个操作数是否可以转换为匹配第二个操作数。如果两者都可以转换,或者其中一个可以转换,但转换是不明确的,则程序是病态的。
"valid"(大双引号)的实现可以像
这样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_; }
};
因此,如果使用强制转换操作符,您将获得指向以空结束的字符串的指针。直到你(比如说)向字符串中添加一个字符为止。然后指针将指向一个非空结束的字符串。或者如果你向字符串中添加了很多字符,它可以释放内存并将其指向其他地方。在这种情况下,您的指针指向可能看起来有效的内容,直到下一次内存分配发生并获取最近释放的内存。
- 如果没有malloc,链表实现将失败
- 如果我只是不访问queue_front节点的子节点,而是将它们推到队列中呢?还是BFS吗
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 设计一个只能由特定类实例化的类(如果可能的话,通过make_unique)
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- 如果编译的源代码是特定于它编译的硬件的,我们如何分发它
- 如果我std::dynamic_pointer_cast并且底层dynamic_cast的结果为null,那么返回的sh
- C++擦除(如果存在)
- 如果"new int"返回"int*",那么为什么"new int[n]"不返回"int**"?
- 在'如果'陈述输出如何正确
- 如果用户输入无效,如何使用字符串变量-C++重复输入命令
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 在C++中使用Cstring反转字符串
- 如果基类包含双指针成员,则派生类的构造函数
- 如果没有数学库,我如何在C++中创建复利公式
- Cstring 在 VS 2012 中不起作用,但如果使用 VS 2012 打开 VC++ 6.0 项目,则可以工作
- 为什么将CString类型转换为wchar_t*会产生一个临时副本?如果我们使用其他类型而不是CString呢?
- 在c++中,如果我通过引用将CString传递给函数并将其分配给另一个CString,它将被截断