我正在使用pimpl-idiom std::unique_ptr
:
class window {
window(const rectangle& rect);
private:
class window_impl; // defined elsewhere
std::unique_ptr<window_impl> impl_; // won't compile
};
Run Code Online (Sandbox Code Playgroud)
但是,我在第304行的第304行收到有关使用不完整类型的编译错误<memory>
:
'
sizeof
'到不完整类型'uixx::window::window_impl
的应用无效' '
据我所知,std::unique_ptr
应该可以使用不完整的类型.这是libc ++中的错误还是我在这里做错了什么?
为什么以下代码有效呢?
struct A {
std::vector<A> subAs;
};
Run Code Online (Sandbox Code Playgroud)
A是不完整的类型,对吧?如果有一个A*s的矢量我会理解.但在这里,我不明白它是如何工作的.它似乎是一个递归的定义.
在以下示例中,f()
返回不完整类型的函数A
被标记为已删除:
struct A;
A f() = delete;
Run Code Online (Sandbox Code Playgroud)
它被 GCC 接受,但不被 Clang 接受,Clang 抱怨道:
error: incomplete result type 'A' in function definition
Run Code Online (Sandbox Code Playgroud)
演示: https: //gcc.godbolt.org/z/937PEz1h3
根据标准,哪个编译器是正确的?
我有一个类应该有一个同一个类的私有成员,如:
class A {
private:
A member;
}
Run Code Online (Sandbox Code Playgroud)
但它告诉我,成员是一个不完整的类型.为什么?如果我使用指针,它不会告诉我不完整的类型,但我宁愿不使用指针.任何帮助表示赞赏
例如:
class B;
class A {
public:
B f();
};
int main(int, char**) {
A a; // no exception and error
return 0;
}
Run Code Online (Sandbox Code Playgroud)
该类A
可能是不完整的类型。
为什么A
这个例子中可以实例化类呢?
f
我知道当代码中调用成员函数时,程序将无法编译。
这个让我想到:
class X;
void foo(X* p)
{
delete p;
}
Run Code Online (Sandbox Code Playgroud)
delete p
如果我们甚至不知道是否X
有可见的析构函数,我们怎么可能呢?g ++ 4.5.1给出了三个警告:
Run Code Online (Sandbox Code Playgroud)warning: possible problem detected in invocation of delete operator: warning: 'p' has incomplete type warning: forward declaration of 'struct X'
然后它说:
注意:即使在定义类时声明析构函数也不会调用析构函数或特定于类的运算符delete.
哇......像g ++一样诊断这种情况需要编译器吗?还是未定义的行为?
c++ pointers forward-declaration delete-operator incomplete-type
以下示例是C中有效的完整翻译单元吗?
struct foo;
struct foo *bar(struct foo *j)
{
return &*j;
}
Run Code Online (Sandbox Code Playgroud)
struct foo
是一个不完整的类型,但我找不到明确禁止在C标准中解除引用不完整类型.特别是,§6.5.3.2说:
一元运算
&
符产生其操作数的地址.如果操作数具有类型''type'',则结果具有类型''指向类型''的指针.如果操作数是一元运算*
符的结果,则不会对该运算符和&
运算符进行求值,结果就好像两者都被省略,除了对运算符的约束仍然适用且结果不是左值.
结果不是左值的事实不是密切相关的 - 返回值不一定是.对*
运营商的限制很简单:
一元*运算符的操作数应具有指针类型.
而对于&
运营商来说:
一元运算
&
符的操作数应该是函数指示符,[]
一元或一元运算*
符的结果,或者是一个左值,它指定一个不是位字段且不用register
存储类说明符声明的对象.
这两个都非常满意,所以结果应该等同于return j;
.
但是,gcc 4.4.5不编译此代码.它反而出现以下错误:
y.c:5: error: dereferencing pointer to incomplete type
Run Code Online (Sandbox Code Playgroud)
这是gcc的缺陷吗?
以下行给出了错误:
Incompatible Types.
List<List<Integer>> output = new ArrayList<ArrayList<Integer>>();
Run Code Online (Sandbox Code Playgroud)
是什么原因?
编辑
我理解如果我将我的第二个ArrayList更改为List,它不会给我错误.我想知道错误的原因.谢谢
首先阅读Herb's Sutters GotW关于C++ 11中pimpl的帖子:
我在理解GotW#101中提出的解决方案时遇到了一些麻烦.据我所知,在GotW#100中辛苦解决的所有问题都复仇了:
的pimpl
成员是外的线的模板,并且定义并不在使用点可见(在class widget
的类定义和隐式生成的特殊成员函数widget
).也没有任何明确的实例化.这将导致链接期间未解决的外部错误.
widget::impl
在实例化定义的点上仍然是不完整的(我认为它实际上根本没有pimpl<widget::impl>::~pimpl()
被实例化,只是被引用).因此std::unique_ptr<widget::impl>::~unique_ptr()
调用delete
指向不完整类型的指针,如果widget::impl
有一个非平凡的析构函数,则会产生未定义的行为.
请解释是什么迫使编译器在widget::impl
完成的上下文中生成特殊成员.因为我看不出它是如何工作的.
如果GotW#101仍然需要widget::~widget()
在实现文件中明确定义,哪里widget::impl
完成,那么请解释"更健壮"的评论(@sehe在他的答案中引用).
我看的GotW#101的核心要求是,包装"消除样板的一些作品",这在我看来(基于该段的其余部分)来表示的widget::~widget()
声明和定义.所以请不要依赖于你的答案,在GotW#101中,那已经消失了!
Herb,如果你停下来,请告诉我是否可以在这里剪切+粘贴解决方案代码以供参考.
考虑以下代码(它是由于此讨论而产生的):
#include <stdio.h>
void foo(int (*p)[]) { // Argument has incomplete array type
printf("%d\n", (*p)[1]);
printf("%d\n", p[0][1]); // Line 5
}
int main(void) {
int a[] = { 5, 6, 7 };
foo(&a); // Line 10
}
Run Code Online (Sandbox Code Playgroud)
GCC 4.3.4 抱怨错误消息:
prog.c: In function ‘foo’:
prog.c:5: error: invalid use of array with unspecified bounds
Run Code Online (Sandbox Code Playgroud)
在GCC 4.1.2相同的错误消息,并且似乎是不变的-std=c99
,-Wall
,-Wextra
.
所以它对表达式不满意p[0]
,但它很满意*p
,尽管这些(理论上)应该是等价的.如果我注释掉第5行,代码会编译并执行我"期望"(显示6
)的内容.
大概有以下之一是真的:
我把钱放在(1)上.
问题:任何人都可以详细说明这种行为吗?
澄清: …