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

发布于 2024-12-17 04:40:29 字数 313 浏览 3 评论 0原文

假设我有一些这样的代码。我应该在那里写什么才能有一个初始化 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") {};

};

let's assume that I have some codes like this. What should I write there in order to have a constructor that initializes a Foo typed object. Thanks. this is the example I am trying to understand http://flylib.com/books/en/2.674.1.140/1/ sorry for the delay.

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

};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

墨落画卷 2024-12-24 04:40:29

非常量引用参数不能将对象作为默认值,因此您唯一可以在“这里写什么?”中写入内容。是对 set 的引用。这意味着你必须在某个地方放一个。

也许你应该这样写:

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 是在没有参数的情况下构造的,这会将集合初始化为空。

顺便说一句,我想不出 set 有多少用途,而且它们都不简单。

A non-const reference parameter cannot have an object as a default value, so the only thing you can write in "what to write here?" is a reference to a set<int*>. This means you'd have to have one lying around somewhere.

Probably you should instead write something like this:

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) {}
};

This will initialize the set empty if a Foo is constructed with no args.

Btw, I can't think of many uses for a set<int*>, and none of them are simple.

轻拂→两袖风尘 2024-12-24 04:40:29

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

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

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

当然,这没有什么意义,因为你可以编写一个无参数构造函数并让数字具有默认值。如果您希望它具有一些初始值,请编写一个填充初始值的函数:

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

I don't know why you're taking the parameter by non-const reference, so until I hear the reason for that, I'll ignore it.

If you want an empty set, you can do this:

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

Of course, there's not much point to that, as you could just write a no-parameter constructor and let numbers have it's default value. If you want it with some initial values, then write a function that populates one:

set<int*> make_numbers() { ... }
Foo(const set<int*>& numb = make_numbers()): numbers(numb) {}
如梦亦如幻 2024-12-24 04:40:29

你可以这样写:

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 类型的默认参数。因此,我尝试为指针的初始化数组编写尽可能少的代码,并使该指针有效。
当然,真正的程序不应该包含这样的代码:

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

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

You can write something like this:

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) {}
};

Note about memory usage:
1)This code just demonstrate how to use default arg of type std::set. So I try to write the smallest code as possible for init array of pointers, and make this pointers valid.
Of course, the real program should not contain such code:

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

2)There are only 3 allocations, and number of them not depend on amout of objects of type Foo. And all this memory will be freed at end of program. And tools like valgrind will mark them as possibly lost, not definetly lost memory.

梦初启 2024-12-24 04:40:29

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

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.

};

Having a set of pointers usually isn't what you want. sets are a collection of unique items, but a set of pointers means each pointer will be unique, not the values they point to.

Steve Jessop points out some more reasons not to want a container of pointers. For one, it's not clear who owns the pointers at what point, and so it's not clear how to handle errors. Part of sorting that out could mean imposing stricter requirements on the pointers, for example requiring them to be new allocated so that the object taking ownership knows how to release them. Such requirements will probably only be enforced by manual inspection of the code and documentation, and so will be error prone. That could be improved on by using smart pointers instead of raw pointers.

But if for some reason you really do want this with raw pointers, then:

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

Or use overloading instead:

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

Or if you really want to construct numbers as a non-empty set by default you can do the following (dangerous, leak prone) things:

   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));
       }
   }

Or using 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

or

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

Fixing the leaks above using smart pointers yields something like:

   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)));
       }
   }

Using brace initialization with smart pointers like the following still has the possibility for leaks:

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

So instead you should use a helper function to produce the default value:

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.

};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文