Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用静态分配的派生类对象初始化基类指针数组_C++_C++17_Stm32 - Fatal编程技术网

C++ 使用静态分配的派生类对象初始化基类指针数组

C++ 使用静态分配的派生类对象初始化基类指针数组,c++,c++17,stm32,C++,C++17,Stm32,我设计了一些类来保存指向某些变量的指针,以及一些与变量相关的其他属性。实际上,我正试图为STM32设计一个CANopen堆栈,并计划使用这些类来表示对象字典 以下是这些类的简化版本: class Object { public: constexpr Object(int index) : index{index} {} private: int index; }; class Single : public Object { public: constexpr Sing

我设计了一些类来保存指向某些变量的指针,以及一些与变量相关的其他属性。实际上,我正试图为STM32设计一个CANopen堆栈,并计划使用这些类来表示对象字典

以下是这些类的简化版本:

class Object {
public:
    constexpr Object(int index) : index{index} {}
private:
    int index;
};

class Single : public Object {
public:
    constexpr Single(int index, void* var, std::size_t size)
    : Object{index}, ptr{var}, size{size} {}
private:
    void* ptr;
    std::size_t size;
};

class Array : public Object {
public:
    constexpr Array(int index, void* var, std::size_t size, std::size_t length)
    : Object{index}, ptr{var}, size{size}, length{length} {}
private:
    void* ptr;
    std::size_t size;
    std::size_t length;
};
我希望创建这些对象的数组。下面的代码编译时没有问题:

int a {1}; // Single variable
float b[] {2.0, 3.0}; // Array

const Object* dictionary[] {
    new Single(0x1000, &a, sizeof(int)),
    new Array(0x1001, b, sizeof(float), std::size(b))
};
问题是,我尽量避免使用堆(动态分配)。在嵌入式系统中使用动态分配是一个有争议的话题,但我主要关心的是内存利用率:STM32微控制器的闪存ROM比RAM多得多,因此最好将变量标记为
const
,这样链接器就可以将它们放入ROM而不是RAM中

但是当一个用户修改代码如下时,它不会编译:

const Object* dictionary[] {
    &Single(0x1000, &a, sizeof(int)),
    &Array(0x1001, b, sizeof(float), std::size(b))
};
它给出
错误:获取右值的地址
错误

我可以想出一个解决办法:

const Single a_obj {0x1000, &a, sizeof(int)};
const Array b_obj {0x1001, b, sizeof(float), std::size(b)};

const Object* dictionary[] {
    &a_obj,
    &b_obj
};

这工作没有问题,并且将
a_obj
&
b_obj
放入ROM。但我认为它看起来很难看。它迫使我定义和维护额外的变量集,想象一下,如果你有大约20个变量会怎么样。有更干净的方法吗?

除非您对堆分配进行规划(正如您所说,这在微控制器上是有争议的),否则您很可能必须按照自己的意愿进行(全局实例化并添加地址)

为什么?
当你谈论指针时,你需要的是指向一个有效的内存块。当您执行类似于
&数组(0x1001,b,sizeof(float),std::size(b))的操作时,您基本上是在尝试访问原始数据的地址(因此出现了声明
右值的错误)

一个简单的例子是

int*pInt=&10;//这基本上就是你所做的。
注意:
rvalue
不严格转换为原始数据

这就是
错误的原因:获取右值的地址

这项工作没有问题,并且将a_obj和b_obj放入ROM。但我认为它看起来很难看。它迫使我定义和维护额外的变量集,想象一下,如果你有大约20个变量会怎么样


无论如何,这是堆分配内存的情况,您必须管理其生命周期。静态实例化它的唯一好处是不必显式删除分配的内存块。

我有点疯狂,所以

template<int index, auto& var>
constexpr Single Single_v{index, std::addressof(var), sizeof(var));
template<class T, std::size_t N>
constexpr Array MakeArray( int index, T(&arr)[N] ) {
  return {index, arr, sizeof(T), N};
}
template<std::size_t index, auto& Arr>
constexpr Array Array_v = MakeArray( index, Arr );

const Object* dictionary[] {
  &Single_v<0x1000, a>,
  &Array_v<0x1001, b>,
};
现在你可以

const Object* dictionary[] {
  &Object_v<0x1000, a>,
  &Object_v<0x1001, b>,
};
const Object*dictionary[]{
&对象(v),
&对象(v),
};
我们得到了编译时多态正确的对象类型

使用模板参数参数可以做的事情有一些限制,但我看不到有任何影响


.

你不能既有蛋糕又吃。如果希望有一个指针数组,其中所有指针都初始化为指向静态分配的对象,则需要在数组之前定义(特别是初始化)对象。因此,你认为这种方法看起来很丑陋。值得庆幸的是,编译器拒绝了您保存临时对象地址的尝试,因为(如果允许编译的话)在初始化数组后,对象将立即不存在,数组将成为悬空指针的集合。顺便说一句,嵌入式系统争论的不只是“使用堆”。实际上,不鼓励的往往是任意分配、取消分配和重新分配的模式。对于不受控制的动态内存分配(分配和取消分配您喜欢的任何内容,只要您喜欢),挑战在于内存消耗没有上限,程序员觉得控制他们的内存分配(不超过定义的内存使用上限)太“严格”,我在这个项目中使用了一些
new
s进行一次性对象初始化,但我从不使用
delete
。对我来说,主要的问题是对常量对象浪费宝贵的RAM。如果使用堆栈分配器呢?像这个@kreuzerkrieg谢谢你的链接,它看起来很有趣,对嵌入式项目肯定很有用。但是,它不能将数据放在STM32的闪存ROM上。为此,必须在编译时创建数据。
const Object* dictionary[] {
  &Object_v<0x1000, a>,
  &Object_v<0x1001, b>,
};