我有一个拥有多种资源的非平凡类型.如何以异常安全的方式构建它?
例如,这是一个X包含以下数组的演示类A:
#include "A.h"
class X
{
unsigned size_ = 0;
A* data_ = nullptr;
public:
~X()
{
for (auto p = data_; p < data_ + size_; ++p)
p->~A();
::operator delete(data_);
}
X() = default;
// ...
};
Run Code Online (Sandbox Code Playgroud)
现在这个特定类的明显答案就是使用std::vector<A>.这是个好建议.但这X只是一个X必须拥有多个资源的更复杂场景的替身,并且使用"使用std :: lib"的好建议并不方便.我选择用这个数据结构来传达这个问题只是因为它很熟悉.
要水晶清楚:如果你可以设计X使得拖欠~X()正确清除了一切("零规则"),或者如果~X()只需要发布一个单一的资源,那是最好的.然而,在现实生活中有时候~X()必须处理多种资源,而这个问题解决了这些情况.
所以这种类型已经有了一个很好的析构函数和一个很好的默认构造函数.我的问题集中在一个非平凡的构造函数,它接受两个A,为它们分配空间,并构造它们:
X::X(const A& x, const A& y)
: size_{2}
, data_{static_cast<A*>(::operator new …Run Code Online (Sandbox Code Playgroud) 实际上,分段错误发生在我试图编译的另一个程序中,这是因为这种行为.
我的问题是:
这是一个错误还是我的错?
可以任何方式重现(即使该something字段是私有的或受保护的),这是我的例子:
main.cc:
#include <iostream>
class Test {
public:
const char* something = "SOMETHING HERE!!!";
Test(const int& number) : Test(something, number) { }
// XXX: changed `something` to `_something` to make it different
Test(const char* _something, const int& number) {
std::cout << _something << std::endl;
std::cout << number << std::endl; }
~Test() { }
};
int main(int argc, char* argv[]) {
Test te1(345);
Test te2("asdasdad", 34523);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
以下是编译时发生的情况:
g++ main.cc -Os -o main
Run Code Online (Sandbox Code Playgroud)
并运行: …
[这个问题经过高度编辑; 请原谅,我已将编辑内容转移到下面的答案]
来自维基百科(包括子文章)在C++ 11上:
这个[ 新的委托构造函数 ]有一个警告:C++ 03认为在构造函数完成执行时要构造一个对象,但是C++ 11在构造函数完成执行后会考虑构造一个对象.由于将允许多个构造函数执行,这意味着每个委托构造函数将在其自己类型的完全构造的对象上执行.派生类构造函数将在其基类中的所有委托完成后执行."
这是否意味着委托链为ctor委托链中的每个链接构造一个唯一的临时对象?为避免简单的init函数定义而产生的这种开销不值得额外开销.
免责声明:我问过这个问题,因为我是学生,但到目前为止答案都是不正确的,并证明缺乏研究和/或对参考研究的理解.我对此感到有些沮丧,因此我的编辑和评论一直匆匆而且写得不好,主要是通过智能手机.请原谅这个; 我希望我在下面的答案中将其最小化,并且我已经了解到我需要在评论中保持谨慎,完整和明确.
在这个响应中,tloveless指出在MSVC中可以使用this->foo::foo(42); 构造函数委托来直接调用构造函数:
#include <iostream>
struct foo
{
int m;
foo(int p) : m(p) { std::cout << "foo("<<p<<")\n"; }
foo()
: m(0)
{
this->foo::foo(42);
std::cout << "foo(), " << m << "\n";
}
};
int main()
{
foo f;
std::cin.ignore();
}
Run Code Online (Sandbox Code Playgroud)
我很惊讶这甚至在MSVC中编译; clang ++,g ++和我同意它是非法的,例如[class.ctor]/2"因为构造函数没有名称,所以在名称查找期间永远找不到它们"
但是,在MSVC12 Update 1(2013)和MSVC10 SP1(2010)中,MSVC甚至不会发出带有/Wall和不带语言扩展的警告/Za.
输出是:
foo(42) foo(), 42
在两个版本中.所以没有临时创建,但是一个名为的构造函数.
问题:
/Za并且扩展列表似乎不这么认为)(我用[delegating-constructors]标签标记了这个问题,因为它让我想起了这个功能)
meta-info:我几乎可以肯定这个问题是重复的,因为这个功能在某种程度上是已知的.例如,请参阅"类似问题"的答案.如果您能找到描述此功能的答案,请不要犹豫,将其作为副本关闭.
struct D
{
virtual void m() const = 0;
};
struct D1 : public virtual D { };
struct D2 : public virtual D { };
struct B : public D2
{
B() { }
B(int val) : B() { }
void m() const { }
};
struct A : public B, public D1
{
A() : B(0) { }
};
int main()
{
A a;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用上面的代码我遇到MSVC 2013编译器崩溃.使用GCC 4.7.2编译时,它运行时没有崩溃.类的层次结构如下所示.
D
/ \
D1 D2
| |
\ …Run Code Online (Sandbox Code Playgroud) c++ virtual-inheritance visual-c++ c++11 delegating-constructor
我知道在纯C++中没有办法做到这一点,但我想知道是否可以从C++/CLI中的另一个构造函数的初始化列表中调用构造函数,就像在C#中可以这样做一样.
例:
ref class Foo {
Foo() {}
Foo(int i) : Foo() {}
}
Run Code Online (Sandbox Code Playgroud) 我有一个A包含大量数据成员的类,其中一些是常量.所有数据成员都有正确的拷贝构造函数,所以我想默认我的类的拷贝构造函数:
class A
{
public:
A() : a(1) {}
A(const A& op) = default;
private:
// ... Lots of constant and non-constant member data ...
const int a;
};
Run Code Online (Sandbox Code Playgroud)
然后,我想编写一个接受引用的构造函数A和一个应该初始化一个常量数据成员的值:
A(const A& op, const int a_);
Run Code Online (Sandbox Code Playgroud)
这里op应该被复制,并且a应该在之后初始化a_或代替复制.我想通过委托给复制构造函数来避免手动初始化所有数据成员,但是在这种情况下如何覆盖我的const数据成员?例如:
// Illegal: constructor delegation can't be mixed with field initialization.
A(const A& op, const int a_) : A(op), a(a_) {}
// Illegal: attempt to assign constant member.
A(const A& op, const int a_) …Run Code Online (Sandbox Code Playgroud) c++ constructor const copy-constructor delegating-constructor
我想要实现这样一个类:
class A{
int a;
int b;
int c;
A():a(),b(),c(){};
A(int ia,int ib,int ic=ia+ib):a(ia),b(ib),c(ic){}; //this is what i need
};
Run Code Online (Sandbox Code Playgroud)
我希望ic的默认值是基于ia和ib计算的,这里的代码在编译时会出错.
我想知道是否有办法得到这样的东西.
谢谢.
c++ constructor default-arguments c++11 delegating-constructor
是否可以在我自己的默认ctor定义中调用聚合初始化?
GCC使用以下代码抱怨"错误:构造函数委托给自己":
struct X {
int x, y, z, p, q, r;
X(): x{}, y{}, z{}, p{}, q{}, r{} { } // cumbersome
//X(): X{} { } // the idea is nice but doesn't compile
};
Run Code Online (Sandbox Code Playgroud)
我现在正在使用memset(this, 0, sizeof(*this))ctor身体.
c++ constructor aggregate-initialization c++11 delegating-constructor
考虑以下程序.我不小心弄错了.
struct T {
int s;
T() : T() {
s=9;
}
};
int main() {
T t;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码在某些版本的g ++中编译和运行,如g ++ 4.8.1(请参阅此处的实时演示)&clang ++ 3.6.0(请参阅此处的实时演示)和MSVC++ 2015,但在运行时崩溃.它给了我分段错误错误.我认为这是由于递归我的意思是递归调用构造函数.但是最新版本的g ++&clang ++无法通过提供以下错误来编译此代码:
g ++ 4.9.2给出以下错误(请参阅此处的实时演示)
prog.cc: In constructor 'T::T()':
prog.cc:3:10: error: constructor delegates to itself
T() : T() {
Run Code Online (Sandbox Code Playgroud)
clang ++给出以下错误(请参阅此处的在线演示)
main.cpp:4:8: error: constructor for 'T' creates a delegation cycle [-Wdelegating-ctor-cycles]
T() : T() {
^
1 error generated.
Run Code Online (Sandbox Code Playgroud)
那么,这里的问题是根据标准,哪个编译器就在这里?这是其中一个编译器的错误吗?上面的程序究竟发生了什么?纠正我如果我在理解的某个地方错了.为什么同一程序在这些编译器的不同版本中表现出不同的行为?
c++ constructor language-lawyer c++11 delegating-constructor
c++ ×9
c++11 ×6
constructor ×5
visual-c++ ×3
c++-cli ×1
c++-faq ×1
const ×1
native ×1
performance ×1