使用va_list创建对象,构造函数

时间:2016-06-03 18:29:03

标签: c++

我遇到了va_list的问题。我在构造函数中使用它来获取意外数量的数据到我的对象。有问题的代码在那里:

#include <cstdarg>
#include <iostream>
using namespace std;

class DATA{
    private:
        int length;
        int* tab;
    public:
        DATA():tab(NULL), length(0){};
        DATA(int x, ...):length(x+1){
            va_list ap;
            va_start(ap, x);
            tab=new int[length];
            for(int i=0; i<length; ++i){
                tab[i]=va_arg(ap, int);
            }
            va_end(ap);
        }
        void showthem()const{
            if(tab!=NULL){
                int x;
                for(x=0; x<length-1; ++x){
                    cout<<tab[x]<<", ";
                }
                cout<<tab[x];
            }
        }
}
ostream & operator<<(ostream & out, const DATA & x){
    x.showthem();
    return out;
}
int main(){
    int table [] = {5,1,2,3,4,5,6};
    DATA x1(*table);
    DATA x2(4,1,2,3,4,5);
    cout << x1 << endl;
    cout << x2 << endl;
}

当我通过编写所有参数自然地创建对象时它没关系,但是当我尝试通过表格来制作它时它会产生问题。 我在课程标签中得到了意想不到的数据。

我想我做错了什么。最糟糕的方式 - 我甚至可以通过* table制作这样的对象吗?我给构造函数一些整数,所以它应该工作...

1 个答案:

答案 0 :(得分:1)

KIIV钉了它。 std::initializer_listdocumentation linked here)正是OP所需要的。

忘记变量参数列表。它们允许以不同的方式进行难以调试的程序。例如,

DATA x2(41,2,3,4,5)

糟糕!错过了一个逗号,并且会在堆栈中读出超出范围的waaaaaay!或者

DATA x2(5, 1,2,3,4,"I am the very model of a modern major-general...")

哪个更易于发现,但仍然可以编译,因为编译器不知道或不关心varadic函数允许的类型。

initializer_list<int>只允许int,您无需指定int的数量。那里有一个更小的潜在错误!

修复一些明显的错误步骤并忽略elephant in the room, std::vector,暂时我们得到的东西看起来像

#include <initializer_list>
#include <iostream>

class DATA{
    private:
        int length;
        int* tab;
    public:
        DATA(std::initializer_list<int> vals):
            length(vals.size()), tab(new int[length])
        {
            int index = 0;
            for(int val: vals){
                tab[index]=val;
                index++;
            }
        }
        DATA(const DATA& src) = delete;
        DATA& operator=(const DATA& src) = delete;

        friend std::ostream & operator<<(std::ostream & out, const DATA & x){
            if(x.tab!=NULL){
                int index=0;
                out<<x.tab[index];
                for(index++; index < x.length; ++index){
                    out<<", "<<x.tab[index];
                }
            }
            return out;
        }
};
int main(){
    DATA x1({1,2,3,4,5});
    std::cout << x1 << std::endl;
}

请注意{}中的DATA x1({1,2,3,4,5});大括号。这会建立列表。列表知道它有多大,所以你不必告诉函数有多少项目即将来临。

请注意,我已删除了复制构造函数和赋值运算符。这是因为三法则。 What is The Rule of Three?阅读链接并了解相关信息。它将为您节省大量未来的调试时间。

这也很容易模板化:

template <class TYPE>
class DATA{
    private:
        int length;
        TYPE* tab;
    public:
        DATA(std::initializer_list<TYPE> vals):
            length(vals.size()), tab(new TYPE[length])
        {
            int index = 0;
            for(const TYPE& val: vals){
                tab[index]=val;
                index++;
            }
        }

        DATA(const DATA& src) = delete;
        DATA& operator=(const DATA& src) = delete;

        friend std::ostream & operator<<(std::ostream & out, const DATA & x){
            if(x.tab!=NULL){
                int index=0;
                out<<x.tab[index];
                for(index++; index < x.length; ++index){
                    out<<", "<<x.tab[index];
                }
            }
            return out;
        }
};

int main(){
    DATA<int> x1({1,2,3,4,5});
    DATA<std::string> x2({"I", "am", "the", "very", "model", "of", "a", "modern", "major-general"});
    std::cout << x1 << std::endl;
    std::cout << x2 << std::endl;
}