MyClass a1 {a}; // clearer and less error-prone than the other three
MyClass a2 = {a};
MyClass a3 = a;
MyClass a4(a);
Run Code Online (Sandbox Code Playgroud)
为什么?
我在SO上找不到答案,所以让我回答一下我自己的问题.
在C++ 11中,我们有了用于初始化类的新语法,它为我们提供了如何初始化变量的大量可能性.
{ // Example 1
int b(1);
int a{1};
int c = 1;
int d = {1};
}
{ // Example 2
std::complex<double> b(3,4);
std::complex<double> a{3,4};
std::complex<double> c = {3,4};
auto d = std::complex<double>(3,4);
auto e = std::complex<double>{3,4};
}
{ // Example 3
std::string a(3,'x');
std::string b{3,'x'}; // oops
}
{ // Example 4
std::function<int(int,int)> a(std::plus<int>());
std::function<int(int,int)> b{std::plus<int>()};
}
{ // Example 5
std::unique_ptr<int> a(new int(5));
std::unique_ptr<int> b{new int(5)};
}
{ // Example 6
std::locale::global(std::locale("")); // copied from 22.4.8.3 …Run Code Online (Sandbox Code Playgroud) 我试图理解这两种初始化方式之间的语义差异:
Foo foo{x};
Foo foo = {x};
Run Code Online (Sandbox Code Playgroud)
我很想知道以下情况的区别:
x是类型的Foo.Foo 有一个构造函数,它接受与x相同类型的参数.x不是类型,Foo但可以使用转换构造函数.x不是类型,Foo但可以使用explicit转换构造函数.根据差异我的意思是,在每种情况下:
这是我经常遇到的RAII问题.我想知道是否有人有一个很好的解决方案.
从标准RAII实用程序类开始:
class RAIIHelper {
RAIIHelper() {
AcquireAResource();
}
~RAIIHelper() {
ReleaseTheResource();
}
};
Run Code Online (Sandbox Code Playgroud)
现在,由于各种原因,我需要将其作为模板.我们还说它的构造函数接受模板参数类型的参数:
template <typename T>
class RAIIHelper {
RAIIHelper(T arg) {
AcquireAResource();
}
~RAIIHelper() {
ReleaseTheResource();
}
};
Run Code Online (Sandbox Code Playgroud)
现在考虑使用网站:
void func() {
RAIIHelper<SomeType> helper(someObj);
}
Run Code Online (Sandbox Code Playgroud)
SomeType当它可以从中推断时必须写出来很烦人someObj,因此我编写了一个辅助函数来推断出类型:
template <typename T>
RAIIHelper<T> makeRAIIHelper(T arg) {
return RAIIHelper<T>(arg);
}
Run Code Online (Sandbox Code Playgroud)
现在我可以像这样使用它:
void func() {
auto helper = makeRAIIHelper(someObj);
}
Run Code Online (Sandbox Code Playgroud)
很棒,对吧?除了有一个障碍:RAIIHelper现在需要是可复制的或可移动的,并且释放资源的析构函数可能被调用两次:一次用于返回的临时值makeRAIIHelper,一次用于调用函数中的局部变量.
实际上,我的编译器执行RVO,并且只调用析构函数一次.但是,这不能保证.这可以从以下事实看出:如果我尝试给出RAIIHelper一个= delete'd move构造函数,代码就不再编译了.
我可以向RAIIHelper添加额外的状态,以便它知道ReleaseTheResource()在移动之后不会调用,但这是额外的工作,在我添加makeRAIIHelper()以获得类型扣除之前是不必要的.
有没有办法可以获得类型演绎,而无需添加额外的状态RAIIHelper …