3

我正在研究一个泛型类型,我需要一个参数类型的堆栈分配数组。它应该尽可能少的开销。这是考试的一部分,但现在它激发了我的好奇心。我试着环顾四周,但我没有找到任何有用的东西。

我正在尝试创建一个数组并初始化成员,但我不完全确定如何正确执行。我有以下代码:

T b[_dim]; // typeof(_dim) == size_t

现在 T 可以是任何具有标准算术运算符、默认构造函数的东西。当 T 是双精度时,我使用以下命令初始化数组:

memset(b, 0, _dim*sizeof(T));

这适用于双打等类型。现在的问题是 T 可能是一个有理数,例如:

方法一

struct Rational
{
   int numerator;  
   int denominator;
   Rational(): numerator(0), denominator(1) {}
};

如果我们在所有内容都设置为 0 后将其转换为双精度值,这可能会导致麻烦。另一种方法是运行所有元素,如下所示:

方法二

for(size_t i = 0; i < _dim; i++)
{
    b[i] = T();
}

正确初始化成员的有效方法是什么?

一个侧面节点是,当我不为理性以外的其他类型做任何事情时。以双打为例。该程序运行良好,但valgrind抱怨以下错误消息(其中很多,重复):

==24450== Conditional jump or move depends on uninitialised value(s)
==24450==    at 0x5878B60: __printf_fp (printf_fp.c:731)
==24450==    by 0x5876B4B: vfprintf (vfprintf.c:1654)
==24450==    by 0x589B654: vsnprintf (vsnprintf.c:119)
==24450==    by 0x53938FD: std::__convert_from_v(__locale_struct* const&, char*, int, char const*, ...) (c++locale.h:93)
==24450==    by 0x53A118C: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (locale_facets.tcc:997)
==24450==    by 0x53A141F: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (locale_facets.tcc:1144)
==24450==    by 0x53A5966: std::ostream& std::ostream::_M_insert<double>(double) (locale_facets.h:2398)
==24450==    by 0x433E9D: void boost::io::detail::put_last<char, std::char_traits<char>, double>(std::basic_ostream<char, std::char_traits<char> >&, double&) (feed_args.hpp:115)
==24450==    by 0x43273E: void boost::io::detail::put<char, std::char_traits<char>, std::allocator<char>, double&>(double&, boost::io::detail::format_item<char, std::char_traits<char>, std::allocator<char> > const&, boost::basic_format<char, std::char_traits<char>, std::allocator<char> >::string_type&, boost::basic_format<char, std::char_traits<char>, std::allocator<char> >::internal_streambuf_t&, std::locale*) (feed_args.hpp:176)
==24450==    by 0x43141F: void boost::io::detail::distribute<char, std::char_traits<char>, std::allocator<char>, double&>(boost::basic_format<char, std::char_traits<char>, std::allocator<char> >&, double&) (feed_args.hpp:253)
==24450==    by 0x42F22F: boost::basic_format<char, std::char_traits<char>, std::allocator<char> >& boost::io::detail::feed<char, std::char_traits<char>, std::allocator<char>, double&>(boost::basic_format<char, std::char_traits<char>, std::allocator<char> >&, double&) (feed_args.hpp:263)
==24450==    by 0x42DB1E: boost::basic_format<char, std::char_traits<char>, std::allocator<char> >& boost::basic_format<char, std::char_traits<char>, std::allocator<char> >::operator%<double>(double&) (format_class.hpp:68)
==24450== 
==24450== Use of uninitialised value of size 8
==24450==    at 0x5878B6A: __printf_fp (printf_fp.c:731)
==24450==    by 0x5876B4B: vfprintf (vfprintf.c:1654)
==24450==    by 0x589B654: vsnprintf (vsnprintf.c:119)
==24450==    by 0x53938FD: std::__convert_from_v(__locale_struct* const&, char*, int, char const*, ...) (c++locale.h:93)
==24450==    by 0x53A118C: std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_float<double>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, char, double) const (locale_facets.tcc:997)
==24450==    by 0x53A141F: std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, double) const (locale_facets.tcc:1144)
==24450==    by 0x53A5966: std::ostream& std::ostream::_M_insert<double>(double) (locale_facets.h:2398)
==24450==    by 0x433E9D: void boost::io::detail::put_last<char, std::char_traits<char>, double>(std::basic_ostream<char, std::char_traits<char> >&, double&) (feed_args.hpp:115)
==24450==    by 0x43273E: void boost::io::detail::put<char, std::char_traits<char>, std::allocator<char>, double&>(double&, boost::io::detail::format_item<char, std::char_traits<char>, std::allocator<char> > const&, boost::basic_format<char, std::char_traits<char>, std::allocator<char> >::string_type&, boost::basic_format<char, std::char_traits<char>, std::allocator<char> >::internal_streambuf_t&, std::locale*) (feed_args.hpp:176)
==24450==    by 0x43141F: void boost::io::detail::distribute<char, std::char_traits<char>, std::allocator<char>, double&>(boost::basic_format<char, std::char_traits<char>, std::allocator<char> >&, double&) (feed_args.hpp:253)
==24450==    by 0x42F22F: boost::basic_format<char, std::char_traits<char>, std::allocator<char> >& boost::io::detail::feed<char, std::char_traits<char>, std::allocator<char>, double&>(boost::basic_format<char, std::char_traits<char>, std::allocator<char> >&, double&) (feed_args.hpp:263)
==24450==    by 0x42DB1E: boost::basic_format<char, std::char_traits<char>, std::allocator<char> >& boost::basic_format<char, std::char_traits<char>, std::allocator<char> >::operator%<double>(double&) (format_class.hpp:68)

采用我的两种方法中的任何一种都使 valgrind 不再抱怨。

更新变量 _dim 确实是变量并被解析。g++11 说:

error: variable-sized object ‘b’ may not be initialized

解决方案和总结 正如所指出的,这调用了所有元素的ctor:

b T[_dim];

由于 _dim 是可变的,因此这不起作用:

b T[_dim] = {};

但我们可以这样做::

T b[_dim];
if(std::is_fundamental<T>::value)
{
    memset(b, 0, _dim*sizeof(T));
}
4

2 回答 2

2

正如stfrabbit已经指出的那样,当您定义数组时,将为您调用默认 ctor。对于以下代码:

#include <iostream>
struct Rational
{
   int numerator;  
   int denominator;
   Rational(): numerator(0), denominator(1)
   {std::cout << "Rational ctor!" << std::endl;}
};

int main()
{
    Rational arr[10];
}

输出是:

Rational ctor!
Rational ctor!
Rational ctor!
Rational ctor!
Rational ctor!
Rational ctor!
Rational ctor!
Rational ctor!
Rational ctor!
Rational ctor!

因此,对于类类型,您无需做任何特别的事情。但是,对于内置类型,没有默认 ctor,因此您需要添加几个大括号,即T b[_dim] = {};对每个元素进行值初始化。通过这样做,它将适用于类类型和内置类型。

于 2013-05-09T20:49:36.767 回答
1

您可以定义覆盖函数来初始化不同的 T,我假设您使用的 c++ 支持覆盖。

void init(double& t)
{
  t = 0;
}
void init(Rational& t)
{
   t.numerator = 0;
   t.denominator= 0;
}

接着:

for(size_t i = 0; i < _dim; i++)
{
    inti(b[i]);
}
于 2013-05-09T20:44:22.053 回答