是否有合理使用函数返回匿名结构?

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)

我想讨论几点:

  1. 很明显,这个代码泄漏,无论如何我不知道底层结构定义是什么而泄漏?见评论[1].
  2. 我必须返回一个指向匿名结构的指针,这样我就可以在模板化函数中创建一个对象的实例,我可以在func不返回指针的情况下做类似的事情吗?
  3. 我想最重要的是,是否有任何(现实世界)用于此?正如上面给出的例子泄漏并且无可否认地做出了设计.

顺便说一下,函数的foo(a,b)作用是返回一个包含两个数字的结构,所有数字的总和从1到a以及a和b的乘积.

也许该行new T可以使用boost :: shared_ptr以某种方式避免泄漏,但我没有尝试过.那会有用吗?

我想我只是想把匿名结构删除为浮点数组,比如float*f = new float [2].哪个可能是错的,正如下面的评论所示,那么可以做些什么呢?我可以删除吗?

我可以在VS2008上"按原样"编译和运行此代码,也许VS可能正在使用某些非标准扩展,但它确实运行并给出15和30作为答案.

从答案我相信这个装置是一个VS2008特定的实体,它不符合标准,因此不便携.太糟糕了,我本来希望看到Stackoverflow或Boost人们想出的伏都教,如果这是他们的武器库:).谢谢大家.

vla*_*adr 9

目前,您的代码不可移植; 例如,它不会构建gcc.

该标准的第14.3.1/2节说:

本地型,没有键,式未命名的类型或类型
从任何这些类型的配混 不应被用作模板-
参数
为模板类型参数.

有关可能的演变,请参阅C++标准核心语言缺陷报告,修订版69文章N2657中的第488项.

更新1

假设您的代码格式正确,那么:

  1. 你可以重写:

    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)
  2. 你可以返回一个匿名的structby-value,只要匿名结构有一个构造函数采用另一种类型(匿名与否,你可以在你的方法体内初始化) - 当然,除了你如何指定匿名结构的构造函数?:)

  3. 除了一种极其复杂的尝试不为结构指定明确名称的方式之外,我看不到真实世界的用途; 一个人通常会使用匿名结构(在C++中不是技术上合法的,但是由各种编译器支持作为扩展)以便不污染命名空间,通常是通过立即实例化(例如,您可以看到一次性仿函数被实例化并传递下来作为匿名结构 - 再次,技术上不合法的C++.)

更新2

感谢您gf链接到C++标准的相关部分,该部分涉及可能未在返回类型中定义的新类型.

更新3

从评论中引出这一点:调用delete[]分配的内存new(而不是new[])是对堆损坏的邀请.调用delete一个你不知道的类型的指针在技术上是未定义的(应该调用哪个析构函数?)但是在POD(你的匿名结构是一个)的情况下,你可以用这种可怕的 hackish方式逃脱它:

 delete (int*)f;
Run Code Online (Sandbox Code Playgroud)

当然,如果您的代码神奇地构造良好,std::auto_ptr那么就能够保留匿名类型,并且会照顾delete正确而优雅地为您打电话.


Geo*_*che 5

您在标准C++中无法做什么 - 根据§8.3.5/ 6(函数声明,C++ 03),返回类型中不允许使用类型定义:

不应在返回或参数类型中定义类型.

在这种情况下,Visual Studio不兼容.