我有代码:
class A {
public:
A() = default;
private:
int i = 1;
};
int main() {
const A a;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它在g ++上编译很好(参见ideone),但在clang ++上失败并出现错误:
const类型'const A'的对象的默认初始化需要用户提供的默认构造函数
我在LLVM错误跟踪器上报告了这个问题,并使其无效.
我认为试图说服铿锵的开发者绝对毫无意义.另一方面,我没有看到这种限制的原因.
任何人都可以建议,如果C++ 11标准以某种方式暗示此代码无效?或者我应该向g ++报告错误?或许在语言规则方面有足够的自由来以多种方式处理这些代码?
什么是c ++中对象的动态初始化?
请用一个简单的例子来解释......
首先,我有一个结构,其中一个值具有默认值
struct S {
int a = 1;
};
Run Code Online (Sandbox Code Playgroud)
当gcc和clang都是非const/non-constexpr时,可以默认构造此类型.在两者之下,std::is_pod<S>::value是false.奇怪的行为如下:
S s1; // works under both
const S s2{}; // works under both
const S s3; // only works in gcc, clang wants a user-provided constructor
Run Code Online (Sandbox Code Playgroud)
以下尝试都没有对clang产生影响:
struct S {
int a = 1;
constexpr S() = default; // defaulted ctor
virtual void f() { } // virtual function, not an aggregate
private:
int b = 2; // private member, really not an aggregate
};
Run Code Online (Sandbox Code Playgroud)
我唯一可以做的就是 …
这与当前的MSVC编译器完美编译:
struct Foo
{
} const foo;
Run Code Online (Sandbox Code Playgroud)
但是,它无法使用当前的g ++编译器进行编译:
error: uninitialized const 'foo' [-fpermissive]
note: 'const struct Foo' has no user-provided default constructor
Run Code Online (Sandbox Code Playgroud)
如果我自己提供默认构造函数,它可以工作:
struct Foo
{
Foo() {}
} const foo;
Run Code Online (Sandbox Code Playgroud)
这是MSVC的另一个案例是过于宽松,还是g ++过于严格?
该锵文档整齐地解释说,
如果类或结构没有用户定义的默认构造函数,C++不允许您默认构造它的const实例([dcl.init],p9)
基本原理是如果const对象未正确初始化,则以后不能更改.以下代码仅具有用户声明的默认构造函数Test,但其所有成员都具有类内初始值设定项,
#include<iostream>
class Test
{
public:
Test() = default;
void print() const { std::cout << i << "\n"; }
private:
int i = 42; // will propagate to the default constructor!
};
int main()
{
Test const t; // <-- Clang chokes on the const keyword, g++ does not
t.print(); // prints 42
}
Run Code Online (Sandbox Code Playgroud)
所以用户提供默认构造函数的基本原理对我来说似乎是多余的.事实上,g ++ 4.8.1确实可以毫无问题地编译它(在线示例),尽管Clang <= 3.2没有.
问题:为什么完整的类内initalizers +用户声明的默认构造函数的组合不足以默认构造一个const对象?是否有针对C++ 14标准的修复程序?
更新:任何人都可以尝试使用Clang 3.3/3.4,看看与Clang …
请使用以下代码:
#include <iostream>
#include <functional>
template <template<typename> class Op>
auto applyOp(const uint8_t lhs, const uint8_t rhs) {
constexpr Op<uint8_t> op;
return op(lhs, rhs);
}
int main() {
std::cout << +applyOp<std::bit_and>(19, 180) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
使用时g++,这个编译并运行得很好.但是会clang++产生错误:
test.cpp:5:27: error: default initialization of an object of const type 'const bit_and<uint8_t>' (aka 'const bit_and<unsigned char>') without a user-provided default constructor
constexpr Op<uint8_t> op;
^
{}
test.cpp:11:19: note: in instantiation of function template specialization 'applyOp<std::bit_and>' requested here
std::cout << +applyOp<std::bit_and>(19, 180) …Run Code Online (Sandbox Code Playgroud) 从C++ 11标准§8.5p6我们得到:
如果程序要求对const限定类型T的对象进行默认初始化,则T应为具有用户提供的默认构造函数的类类型.
下面的代码应该不会编译.但它确实在Coliru和Ideone都有.
class A{};
int main() {
const A a;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
在尝试理解这里发生了什么时,我最终得到了以下代码,它编译(至少它符合标准,与A用户提供的构造函数一样).但后来出现了以下问题:哪个标准子句确保a.b.j用0初始化(参见Ideone中的代码),下面是什么?
#include <iostream>
struct B { int j; B(){ std::cout << "B()" << '\n'; } };
struct A
{
struct B b;
int i;
public:
A(): i(1) { std::cout << "A()" << '\n'; }
};
int main() {
const A a;
std::cout << a.b.j << '\n';
std::cout << a.i << '\n';
}
Run Code Online (Sandbox Code Playgroud)
EDIT1:
很抱歉上面的编辑,但我还没有使用Unix.上周, …
在 C++ 中,要声明具有成员变量 as 的类的对象const,我们必须有一个用户定义的默认构造函数。下面的代码说明了这一点。
class Some {
int value;
};
int main() {
// error: default initialization of an object of const type 'const Some'
// without a user-provided default constructor
const Some some;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果类拥有的成员变量被限定为可变的,编译器将不会报告任何错误。作为参考,我使用命令编译clang++ -std=c++17 -stdlib=libc++ helloworld.cpp -o helloworld.out --debug。我想知道这个结果是由于编译器中的错误还是根据C++语言中定义的语法。
class Some {
mutable int value;
};
int main() {
const Some some;
return 0;
}
Run Code Online (Sandbox Code Playgroud) 考虑一下代码:
struct Foo
{
int x = 10;
};
int main()
{
const Foo foo;
}
Run Code Online (Sandbox Code Playgroud)
它在g ++ http://coliru.stacked-crooked.com/a/99bd8006e10b47ef下汇编,但在clang ++ http://coliru.stacked-crooked.com/a/93f94f7d9625b579下吐出错误:
error: default initialization of an object of const type
'const Foo' requires a user-provided default constructor
Run Code Online (Sandbox Code Playgroud)
我不确定谁在这里.为什么我们需要一个默认的ctor,因为我们执行了类内初始化?
clang++没有用户定义的构造函数,它不允许默认初始化类型的const变量 ; g++限制性稍差(见下文).根据这个答案,这是因为POD类型"默认情况下没有初始化".如果我理解正确,这意味着默认初始化不会调用默认构造函数,也不会调用值初始化,因此POD类型中的数据成员不会被初始化.当然,使用带有未初始化值的const POD类型是没有意义的,因为它们永远不会被初始化,因此使用起来不安全.
这种情况有一些变种:
clang++并不认为这是一种特殊情况,我认为也不是标准的,但g++也允许它,即使构造函数被标记explicit.){}.(这是clang描述问题的页面上的推荐解决方法.)=default.(C++ 11以后;类型仍然被认为是POD,因此编译器和标准都不会将其视为特殊情况.){},(如果我理解正确)变为值初始化.(C++ 11以后;两个编译器 - 我认为,标准 - 允许这个.)在第一种情况下,可能没有未初始化的成员,因此不清楚为什么任何类本身的实例化都将被视为"未初始化",而不管它是否是const.既然g++允许这种行为,使用安全吗?为什么禁止clang++和标准?(还有其他任何情况g++允许POD默认初始化哪里clang++没有?)
在第二和第三种情况下,使用{}代替的要求=default对我来说似乎很奇怪.编辑: 这个问题很好地解释了差异,所以我已经删除了询问区别的部分问题.(尽管如此,我仍然认为这是一种非常令人困惑的语言方面.)
最后,将Foo f{}始终是零初始化内置类型的成员如果Foo::Foo(void)是{},=default或隐式声明的?
可能有人已经问过这个问题,但在谷歌上搜索“默认”、“默认”、“明确”等并没有给出好的结果。但无论如何。
我已经知道显式定义的默认构造函数(即没有参数)和显式定义的默认构造函数(即带有关键字default)之间存在一些差异,从这里开始:C++11 中的新关键字 =default
但是显式定义的默认构造函数和隐式定义的构造函数(即当用户根本不编写它时)之间有什么区别?
class A
{
public:
A() = default;
// other stuff
};
Run Code Online (Sandbox Code Playgroud)
对比
class A
{
// other stuff
};
Run Code Online (Sandbox Code Playgroud)
想到的一件事是,当存在非默认构造函数时,用户还必须明确定义默认构造函数。但是还有其他区别吗?
编辑:我最感兴趣的是知道是否有任何充分的理由来编写A() = default;而不是完全省略构造函数(当然,假设它是该类唯一明确定义的构造函数)。
我正在学习C++,我对int变量的初始化感到有点困惑.
这段代码(包括注释)是Nawaz在本主题中的答案的复制/粘贴为什么C++需要用户提供的默认构造函数来默认构造一个const对象?
struct POD
{
int i;
};
POD p1; //uninitialized - but don't worry we can assign some value later on!
p1.i = 10; //assign some value later on!
POD p2 = POD(); //initialized
Run Code Online (Sandbox Code Playgroud)
对于p2,我了解到以下情况:
但是,评论说p2已初始化!欢迎任何解释.谢谢.
考虑以下示例:
#include <iostream>
#include <type_traits>
struct A
{
//A() = default; // does neither compile with, nor without this line
//A(){}; // does compile with this line
int someVal{ 123 };
void foobar( int )
{
};
};
int main()
{
const A a;
std::cout << "isPOD = " << std::is_pod<A>::value << std::endl;
std::cout << "a.someVal = " <<a.someVal << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这可以用g ++编译,但不能用clang ++编译,尝试使用以下命令: clang++ -std=c++11 -O0 main.cpp && ./a.out
从clang编译错误:
main.cpp:19:13:错误:const类型'const A'对象的默认初始化需要用户提供的默认构造函数
我从这个Stack Overflow问题中了解到,非POD类获得默认构造函数.这甚至不是必需的,因为变量具有c ++ …