在初始化列表中从float *设置double []

时间:2011-07-26 11:15:18

标签: c++ arrays floating-point double memory-alignment

我的课程看起来大致如下:

template<std::size_t dim>
class Foo {
public:
    Foo(void const * const data);
private: 
    double vals[dim];
}

对于构造函数,我知道void* data指向一个float值数组(维度为dim)。现在我想在该构造函数的初始化列表中初始化vals - 数组(最好)。

更糟糕的是,指向的浮点数不一定必须与内存对齐。

我怎么能有效地做到这一点?


编辑1

关于下面的讨论,请允许我先说明我的设计优先事项。这可能有助于您专注于对我来说最重要的问题。

  1. 应对错误的内存对齐
  2. 在性能方面尽可能少地进行操作。
  3. 老实说,如果我们需要构造函数体来获得快速算法,这对我来说也没问题。重点是原始力量。

4 个答案:

答案 0 :(得分:1)

如果您担心传递的指针未与float边界对齐(例如,文件映射等),那么您可以编写类似

的内容
template<std::size_t dim>
class Foo {
public:
    Foo(void const * const data)
    {
        float temp[dim];
        memcpy( &temp, data, dim * sizeof( float ) );
        std::copy( temp, temp + dim, vals );
    }
private: 
    double vals[dim];
}

可能是一个过于热心且不那么便携的解决方案:

template<std::size_t dim>
class Foo {
public:
    Foo(void const * const data)
    {
        if( static_cast<long>( data ) % sizeof( float ) == 0 ) {
            const float *temp = data;
            std::copy( temp, temp + dim, vals );
        } else {
            float temp[dim];
            memcpy( &temp, data, dim * sizeof( float ) );
            std::copy( temp, temp + dim, vals );
        }
    }
private: 
    double vals[dim];
}

在初始化列表中初始化不会使您的代码更快,只有在可能的情况下才是方便。

如果您非常关注性能,我会将此if包装在一个宏中,并且仅在架构上使用if,这需要正确对齐访问(x86不是一个,它只是慢一点在x86)。

修改

评论中提出的另一个解决方案,谢谢 Steve Jessop。它侧重于减少临时变量大小。

double *dest = vals;
float tmp;
void const *first = data;
void const *last = data + dim * sizeof(float);
while( first != last ) {
    memcpy( &tmp, first, sizeof(float) );
    first += sizeof(float);
    *dest++ = tmp;
}

可能需要进行一些微观基准/分解。

答案 1 :(得分:0)

由于float的大小与double不同,我认为唯一的方法是从一个数组手动分配到另一个数组。

是否可以将vals更改为float的数组?这样您就可以使用datamemcpy数组复制到其中。因为在float数组中存储double时没有精确度,除非您稍后更改vals以使用double的高精度,否则不会从使用double s获得任何东西。

答案 2 :(得分:0)

你为什么要隐藏这个类型?

这有什么问题:

template<std::size_t dim>
class Foo {
public:
    Foo(float const * const data);
private: 
    double vals[dim]
}

template<std::size_t dim>
Foo< dim >::Foo(float const * const data) : vals()
{
  std::copy( data, data+dim, &vals[0] );
}

修改

如果您切换到std::vector,则可以像这样初始化:

class Foo {
public:
    Foo(float const * const dataBegin,float const * const dataEnd);
private: 
    std::vector< double > vals;
}

Foo::Foo(float const * const dataBegin,float const * const dataEnd) : vals( dataBegin, dataEnd )
{
}

答案 3 :(得分:0)

您无法在当前C ++标准的初始化列表中初始化数组。您可以利用事先知道尺寸的事实来使用std::vector;

template<std::size_t dim>
class Foo {
public:
  Foo(float const * const data) : vals(dim) // fix the vector size
  {
    for(std::size_t i=0; i<dim; i++)
      vals[i] = data[i];  // assignment
  }
private: 
  std::vector<double> vals;
};

我不能说vector<>和原始数据一样有效;但它们经过了很好的优化和异常安全。