Aka*_*ksh 7 c++ templates memory-leaks anonymous-types
这是一个使用函数的(人工)示例,该函数返回一个匿名结构并执行"有用"的东西:
#include <iostream>
template<typename T>
T* func(T* t, float a, float b) {
if(!t) {
t = new T;
t->a = a;
t->b = b;
} else {
t->a += a;
t->b += b;
}
return t;
}
struct {
float a, b;
}* foo(float a, float b) {
if(a==0) return 0;
return func(foo(a-1,b), a, b);
}
int main() {
std::cout << foo(5,6)->a << std::endl;
std::cout << foo(5,6)->b << std::endl;
void* v = (void*)(foo(5,6));
//[1] delete f now because I know struct is floats only.
float* f = (float*)(v);
std::cout << f[0] << std::endl;
std::cout << f[1] << std::endl;
delete[] f;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我想讨论几点:
func不返回指针的情况下做类似的事情吗?顺便说一下,函数的foo(a,b)作用是返回一个包含两个数字的结构,所有数字的总和从1到a以及a和b的乘积.
也许该行new T可以使用boost :: shared_ptr以某种方式避免泄漏,但我没有尝试过.那会有用吗?
我想我只是想把匿名结构删除为浮点数组,比如float*f = new float [2].哪个可能是错的,正如下面的评论所示,那么可以做些什么呢?我可以删除吗?
我可以在VS2008上"按原样"编译和运行此代码,也许VS可能正在使用某些非标准扩展,但它确实运行并给出15和30作为答案.
从答案我相信这个装置是一个VS2008特定的实体,它不符合标准,因此不便携.太糟糕了,我本来希望看到Stackoverflow或Boost人们想出的伏都教,如果这是他们的武器库:).谢谢大家.
目前,您的代码不可移植; 例如,它不会构建gcc.
该标准的第14.3.1/2节说:
本地型,没有键,式未命名的类型或类型
从任何这些类型的配混 不应被用作模板-
参数为模板类型参数.
有关可能的演变,请参阅C++标准核心语言缺陷报告,修订版69和文章N2657中的第488项.
假设您的代码格式正确,那么:
你可以重写:
std::cout << foo(5,6)->a << std::endl;
Run Code Online (Sandbox Code Playgroud)
如
std::cout << std::auto_ptr(foo(5,6))->a << std::endl;
Run Code Online (Sandbox Code Playgroud)你可以返回一个匿名的structby-value,只要匿名结构有一个构造函数采用另一种类型(匿名与否,你可以在你的方法体内初始化) - 当然,除了你如何指定匿名结构的构造函数?:)
除了一种极其复杂的尝试不为结构指定明确名称的方式之外,我看不到真实世界的用途; 一个人通常会使用匿名结构(在C++中不是技术上合法的,但是由各种编译器支持作为扩展)以便不污染命名空间,通常是通过立即实例化(例如,您可以看到一次性仿函数被实例化并传递下来作为匿名结构 - 再次,技术上不合法的C++.)
感谢您gf链接到C++标准的相关部分,该部分涉及可能未在返回类型中定义的新类型.
从评论中引出这一点:调用delete[]分配的内存new(而不是new[])是对堆损坏的邀请.调用delete一个你不知道的类型的指针在技术上是未定义的(应该调用哪个析构函数?)但是在POD(你的匿名结构是一个)的情况下,你可以用这种可怕的 hackish方式逃脱它:
delete (int*)f;
Run Code Online (Sandbox Code Playgroud)
当然,如果您的代码神奇地构造良好,std::auto_ptr那么就能够保留匿名类型,并且会照顾delete正确而优雅地为您打电话.
您在标准C++中无法做什么 - 根据§8.3.5/ 6(函数声明符,C++ 03),返回类型中不允许使用类型定义:
不应在返回或参数类型中定义类型.
在这种情况下,Visual Studio不兼容.