如何编写构造函数来初始化一组指针

时间:2011-11-19 23:44:44

标签: c++ g++

我们假设我有一些像这样的代码。我应该在那里写什么才能有一个初始化Foo类型对象的构造函数。谢谢。这是我试图理解的例子http://flylib.com/books/en/2.674.1.140/1/抱歉延迟。

class Foo
{
private:
   set<int*> numbers;
public:
   //constuctor
   Foo(set<int*>& numb = "what to write here?"): numbers("something") {};

};

4 个答案:

答案 0 :(得分:4)

非const引用参数不能将对象作为默认值,因此您可以在“此处写什么?”中写出唯一的内容。是对set<int*>的引用。这意味着你必须在某处躺着。

可能你应该写这样的东西:

class Foo {
    std::set<int*> numbers;
  public:
    Foo() {}
    Foo(const std::set<int*> &numb) : numbers(numb) {}
    // maybe this too
    template <typename InputIterator>
    Foo(InputIterator start, InputIterator end) : numbers(start,end) {}
};

如果构造Foo没有args,则会将该集初始化为空。

顺便说一句,我想不出set<int*>的许多用途,而且没有一个是简单的。

答案 1 :(得分:3)

我不知道你为什么要通过非const引用来获取参数,所以在我听到原因之前,我会忽略它。

如果你想要一个空集,你可以这样做:

Foo(const set<int*>& numb = set<int*>()): numbers(numb) {}

当然,没有太多意义,因为你可以写一个无参数的构造函数,让数字有它的默认值。如果你想要它有一些初始值,那么写一个填充一个的函数:

set<int*> make_numbers() { ... }
Foo(const set<int*>& numb = make_numbers()): numbers(numb) {}

答案 2 :(得分:2)

你可以这样写:

static int *arr[] = { new int(1), new int(2), new int(3) };

class Foo {
private:
std::set<int*> numbers;
public:
Foo(const std::set<int*>& numb = std::set<int *>(arr, arr + (sizeof(arr) / sizeof(arr[0])))): numbers(numb) {}
};

关于内存使用情况的说明:
1)此代码演示了如何使用std :: set类型的默认arg。所以我尝试尽可能为init指针数组编写最小的代码,并使这个指针有效。 当然,真正的程序不应该包含这样的代码:

static int *arr[] = { new int(1), new int(2), new int(3) };

2)只有3个分配,并且它们的数量不依赖于Foo类型的对象的数量。所有这些内存将在程序结束时释放。像valgrind这样的工具会将它们标记为可能丢失,而不是绝对丢失的记忆。

答案 3 :(得分:1)

拥有一组指针通常不是你想要的。 sets是一组唯一项,但是一组指针意味着每个指针都是唯一的,而不是它们指向的值。

Steve Jessop指出了一些不想要指针容器的理由。首先,目前还不清楚谁在哪个点拥有指针,因此不清楚如何处理错误。对其进行排序的一部分可能意味着对指针施加更严格的要求,例如要求对它们进行新分配,以便获取所有权的对象知道如何释放它们。这些要求可能只会通过手动检查代码和文档来强制执行,因此容易出错。这可以通过使用智能指针而不是原始指针来改进。

但是如果出于某种原因你确实想要这个原始指针,那么:

   Foo(set<int*> const &numb = set<int*>()): numbers(numb) {}

或者使用重载:

   Foo() {} // default constructs numbers
   Foo(set<int*> const &numb) : numbers(numb) {}

或者,如果您确实希望默认情况下将数字构造为非空集,则可以执行以下操作(危险,易泄漏):

   Foo(set<int*> const &numb = set<int*>()) : numbers(numb) {
       if(numbers.empty()) { // this also prevents the user from being able to make the set empty
           numbers.insert(new int(0));
           numbers.insert(new int(0));
       }
   }

或者使用C ++ 11:

   Foo(set<int*> const &numb = set<int*>{new int(0),new int(0)} ) : numbers(numb) {} // uses default argument value with brace initializer list style

   Foo(set<int*> const &numb) : numbers(numb) {}
   Foo() : Foo(set<int*>{new int(0),new int(0)}) {} // uses delegating constructors

使用智能指针修复上面的泄漏产生类似于:

   Foo(set<unique_ptr<int>> const &numb = set<unique_ptr<int>>()) : numbers(numb) {
       if(numbers.empty()) { // this also prevents the user from being able to make the set empty
           numbers.insert(unique_ptr<int>(new int(0)));
           numbers.insert(unique_ptr<int>(new int(0)));
       }
   }

使用带有智能指针的大括号初始化(如下所示)仍有泄漏的可能性:

   Foo(set<unique_ptr<int>> const &numb = set<int*>{unique_ptr<int>(new int(0)),unique_ptr<int>(new int(0))} ) : numbers(numb) {}

因此,您应该使用辅助函数来生成默认值:

class Foo
{
private:
    set<unique_ptr<int>> numbers;
    static set<unique_ptr<int>> default_set() {
        set<unique_ptr<int>> the_default;
        the_default.insert(unique_ptr<int>(new int(0)));
        the_default.insert(unique_ptr<int>(new int(0)));
        return the_default;
    }
public:
    // using default arg
    Foo(set<unique_ptr<int>> &&numb = default_set()) : numbers(move(numb)) {};

    // or delegating constructors
    Foo(set<unique_ptr<int>> &&numb) : numbers(move(numb)) {};
    Foo() : Foo(default_set()) {}

    // in addition to one of the above you probably want a constructor that takes a non-rvalue-reference and copies it
    Foo(set<unique_ptr<int>> numb) : Foo(move(numb)) {}; // copy is implicit, we delegate moving that copy into number to the ctor that takes an rvalue-reference. You could also just initialize numbers here directly.

};