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