为啥 alloca 两次返回相同的地址?

Posted

技术标签:

【中文标题】为啥 alloca 两次返回相同的地址?【英文标题】:Why is alloca returning the same address twice?为什么 alloca 两次返回相同的地址? 【发布时间】:2021-05-26 17:47:09 【问题描述】:

我正在尝试实现自己的数学库,并且从向量开始。这个想法是给类一个指向数字数组的指针,然后复制数组并将其存储在私有变量指针给出的数据地址中。首先,我使用alloca 尝试为私有变量释放一些内存

vml.h

namespace vml 
    // Vectors
    template <typename in_type, const int in_length>
    class vec 
    public:
        vec(in_type* in_data) 
            std::cout << data << std::endl;
            std::copy(in_data, in_data + in_length, data);
        
        vec() 
            data = nullptr;
        
        in_type& operator()(int index) const 
            _ASSERT(0 <= index && index < in_length);
            return data[index];
        

    private:
        in_type* data = alloca(in_length * sizeof(in_type));
    ;

ma​​in.cpp

int main() 
    int list[] =  1,2,3 ;
    int list2[] = 2,4,6 ;

    vml::vec<int, 3> a(list);
    vml::vec<int, 3> b(list);

    return 0;

这不会出错,但是由于某种原因,alloca 在调用两个实例时会两次返回相同的地址。我到处搜索这个,我找不到解释为什么。所以我决定使用数组分配内存。如果你能回答这个问题,那将是非常有帮助的。 谢谢。

【问题讨论】:

您确实将operator() 声明为const 1st) 使用alloca()(在 C++ 中)通常是个坏主意。 2nd) 对成员变量使用alloca() 在我看来是一个特别糟糕的主意。考虑到alloca() 是用于临时的。函数中的本地存储(在 C 中)...(我记得 alloca() 只是为了确保我没有遗漏或混淆某些东西...) 这看起来很相关:***.com/a/1029951/4117728 无法重现(即使有修复以使代码编译)您在第一种情况下描述的行为。错误消息是因为无法返回对const 对象的(非可变)成员的非const 引用。将operator() 的返回类型更改为const in_type &amp;。赋值data = nullptr 在第二种情况下也不应该编译,但你没有提到。 当您使用编译时间常数作为数据长度时,只需将手动内存管理替换为 std::array 这将根据您的需要将数据放在堆栈上。 【参考方案1】:

您不能将alloca 包装在一个函数中并将其指针返回到外部,因为包装函数的堆栈将被释放。

如果你调用它作为成员初始化器,它实际上是从构造函数中调用的,并且可能在构造函数返回时被释放,然后被重新使用。

【讨论】:

但是我没有在函数中调用 alloca @JoshuaPasa,它实际上被称为初始化列表的自动生成部分,它是构造函数的一部分【参考方案2】:

让我们从基础开始,您的堆栈很可能只有 1 MB,因此在几个向量和递归调用之后,您的程序可能会死掉。

如果你想在堆栈上解决它,你可以使用std::array 作为data

警告未测试的代码

template <typename in_type, const int in_length>
class vec 
public:
    vec(in_type* in_data) 
        std::cout << data << std::endl;
        std::copy(in_data, in_data + in_length, data);
    
    vec() = default;
    in_type& operator()(int index) const 
        _ASSERT(0 <= index && index < in_length);
        return data[index];

    

private:
  std::array<in_type, in_length> data;
;

或者,如果您想使用std::array 中的所有好东西

template <typename in_type, const int in_length>
class vec : public std::array<in_type, in_length> 
public:
  using std::array::array; // use constructors, might need template param to compile

这也意味着,如果您在某个时候只想更改为堆,则只需将您的 vec 分配为其他所有类。

另一种选择是使用 C++17 PMR,使用堆栈上的分配作为存储并使vec PMR 感知。

【讨论】:

那么vector不只是一个包装器吗? @JoshuaPasa 的想法是您可以扩展功能。【参考方案3】:

你必须非常小心alloca。它在堆栈而不是堆上分配内存。一旦调用alloca 的函数退出,该内存就会被释放。在这种情况下,它将在构造函数中调用,因此当您调用 operator() 时,该内存已被释放并且您正在处理未定义的行为。

除非您确实需要避免堆分配,并且您确定不会溢出堆栈并且您了解使用 alloca 的所有限制,否则最好避开它。

【讨论】:

我想在堆栈上分配内存,因为我不需要向列表中添加更多数据 @JoshuaPasa 你可能想看看这个问题:***.com/questions/354442/… 我在构造函数之外调用了alloca,所以它不应该一直存在直到类实例超出范围吗? @JoshuaPasa - 当您在类中使用该初始化语法时,我不确定分配发生的确切位置。我相信这是构造函数调用的一部分,但您必须咨询语言律师。无论如何,alloca 实际上是 C 运行时的一部分。它没有类的概念。 @Ferruccio 有什么方法可以使用 alloca,这样只有在类超出范围时才会释放它。有点像如何释放类中的变量。这就是为什么我想使用in_type data[in_length],但由于某种原因,即使我没有在前缀中添加const,它也会初始化为常量,但是,它确实解决了内存地址的问题

以上是关于为啥 alloca 两次返回相同的地址?的主要内容,如果未能解决你的问题,请参考以下文章

返回分配指针

为啥添加单个文档时,Firestore 侦听器会返回 .add 两次?

在 SQL 中,为啥这个 JOIN 会两次返回键列?

当返回指向本地数组的指针时,为啥它总是相同的值?

Haskell检查函数是不是两次返回相同的值

两次密码错误如何返回相同状态