我在shared_ptr和weak_ptr一起使用时遇到了麻烦enable_shared_from_this。
当我用Google搜索所见事物的症状时,每个人都建议“ shared_from_this()当没有shared_ptr实例拥有您的对象时,您将无法使用。
但这不是我的情况。
考虑以下代码:
#include <memory>
#include <cassert>
class MyClass : std::enable_shared_from_this<MyClass>
{
public:
void this_fails()
{
// Doesn't even assert(), because it throws bad_weak_ptr
assert(shared_from_this());
}
void this_fails_too()
{
std::weak_ptr<MyClass> weak = weak_from_this();
std::shared_ptr<MyClass> strong = weak.lock();
// This assert fails
assert(strong.get());
}
};
int main()
{
std::shared_ptr<MyClass> obj = std::make_shared<MyClass>();
obj->this_fails();
obj->this_fails_too();
}
Run Code Online (Sandbox Code Playgroud)
两种方法都会MyClass使程序崩溃。我一定缺少明显的东西-这是什么?
c++ shared-ptr weak-ptr private-inheritance enable-shared-from-this
我始终认为私有继承仅仅意味着类型不会告诉外部它是从某个基类继承的。不过,似乎还有更多的限制。
考虑以下最小示例:
struct MyInterface {};
struct MyImpl : private MyInterface {};
struct Inherited : public MyImpl {
// Error: 'MyInterface' not accessible because 'MyImpl' uses 'private' to inherit from 'MyInterface'
void doSomething(MyInterface* mi) {}
};
struct Noninherited {
// All fine!
void doSomething(MyInterface* mi) {}
};
Run Code Online (Sandbox Code Playgroud)
Clang、GCC 和 MSVC 都拒绝此代码。鉴于我之前的假设,我本以为一切都会好起来的。
doSomething只是需要一个指向 的指针MyInterface,但它不会告诉外界其继承层次结构中Inherited有哪些MyInterface内容。在我看来,私有继承不仅不告诉外界继承结构,反而使整个继承结构完全“忘记”继承类型的存在。
这是理解私有继承的正确“思维模型”吗?还有其他意想不到的限制吗?
请参阅以下代码
struct A { using type = int; };
struct B : private A {};
struct C : B { using base_type = A; };
Run Code Online (Sandbox Code Playgroud)
所有的gcc 6.1,clang 3.8和msvc 2015更新3都拒绝编译它,因为A它不是一个可访问的名称,C因为它A是一个私有基础B.似乎gcc认为A是using base_type = A指默认构造函数A.msvc和clang似乎没有.
也许编译错误是由于继承触发的名称注入(因为修改using base_type = A为using base_type = ::A使所有编译器工作正常),但我想知道这个奇怪的错误是否是标准所说的.
更具体地说,
A::type,A只是一个类名(虽然gcc误解为一个函数名),它不是引入C 内部 A也不引入B.为什么这个名字被认为是私人的B?由于第三方库的布局,我有类似下面的代码:
struct Base
{
static void SomeStaticMethod(){}
};
struct Derived1: private Base {};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Base::SomeStaticMethod();
}
};
int main() {
Derived2 d2;
d2.SomeInstanceMethod();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用MSVC获得编译器错误C2247:
Base :: SomeStaticMethod无法访问,因为Derived1使用private从Base继承.
我知道我不能访问Base从成员Derived2通过继承,因为私人符,但我仍然应该能够调用静态方法Base-无论之间的继承关系Base和Derived2.
如何解决歧义并告诉编译器我只是调用静态方法?
在下面的代码中,似乎类C无法访问A的构造函数,这是因为虚拟继承所必需的.然而,代码仍然编译和运行.它为什么有效?
class A {};
class B: private virtual A {};
class C: public B {};
int main() {
C c;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此外,如果我从A中删除默认构造函数,例如
class A {
public:
A(int) {}
};
class B: private virtual A {
public:
B() : A(3) {}
};
Run Code Online (Sandbox Code Playgroud)
然后
class C: public B {};
Run Code Online (Sandbox Code Playgroud)
会(意外地)编译,但是
class C: public B {
public:
C() {}
};
Run Code Online (Sandbox Code Playgroud)
不会像预期的那样编译.
使用"g ++(GCC)3.4.4(cygming special,gdc 0.12,使用dmd 0.125)编译的代码",但已经验证它与其他编译器的行为相同.
c++ inheritance encapsulation virtual-inheritance private-inheritance
我可以这样做吗?
class A { ... };
class B : private A
{
const A &foo() const
{
return *((const A *)this);
}
};
Run Code Online (Sandbox Code Playgroud)
我可以从基类中私有地继承并将其强制转换为其基类的公共版本吗?如果没有虚拟方法,我可以这样做吗?
我的猜测是肯定的,但我想确保它安全/便携.
我正在玩一些使用shared_ptr和enable_shared_from_this,而我遇到了一些我不太懂的东西.
在我的第一次尝试中,我构建了这样的东西:
class shared_test : std::enable_shared_from_this<shared_test> {
public:
void print(bool recursive) {
if (recursive) {
shared_from_this()->print(false);
}
std::cout << "printing" << std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)
请注意,此类私有地扩展std :: enable_shared_from_this.这显然有很大的不同,因为执行这样的事情:
int main() {
auto t(std::make_shared<shared_test>());
t->print(true);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
抛出bad_weak_ptr异常.好像我从std :: enable_shared_from_this中将类定义更改为公开的,这就是find.
为什么,我在这里想念什么?并没有办法使它适用于私有继承,因为shared_test类的"外部世界"不需要知道它是否允许共享...(至少,如果你问我,还是我又想念一些东西?)
c++ shared-ptr private-inheritance c++11 enable-shared-from-this
背景信息:这是在Visual Studio 2008上检测到的,并在Visual Studio 2013上再次确认.G ++在代码中尖叫,而Visual以静默方式接受私有继承泄露.
因此,在Visual C++上,我们有以下代码:
class Base {};
class Derived : Base {}; // inherits privately. Adding explicitly the
// keyword private changes nothing
int main()
{
std::auto_ptr<Base>(new Derived) ; // compiles, which is NOT EXPECTED
std::auto_ptr<Base> p(new Derived) ; // Does not compile, which is expected
}
Run Code Online (Sandbox Code Playgroud)
为什么第一个(临时)auto_ptr会编译?我在调试中进入它,它确实完成了对公共继承应该做的事情(调用正确的构造函数等)
想知道问题是否与auto_ptr实现有关(我们永远不知道......),我减少了这个独立代码的问题:
class Base {};
class Derived : Base {};
template <typename T>
class Ptr
{
T * m_p;
public :
Ptr(T * p_p)
: m_p(p_p)
{
}
} …Run Code Online (Sandbox Code Playgroud) 我有以下不编译的代码示例:
#include <stdio.h>
namespace my
{
class base1
{ // line 6
};
class base2: private base1
{
};
class derived: private base2
{
public:
// The following function just wants to print a pointer, nothing else!
void print(base1* pointer) {printf("%p\n", pointer);}
};
}
Run Code Online (Sandbox Code Playgroud)
gcc打印的错误是:
test.cpp:6:错误:`class my :: base1'无法访问
test.cpp:17:错误:在此上下文中
现在,我可以猜出问题是什么:在查看声明时print,编译器会看到base1并认为:base1是基类子对象derived* this,但是您无法访问它!虽然我打算这base1应该只是一个类型名称.
我怎么能在C++标准中看到这是一个正确的行为,而不是编译器中的错误(我确定它不是一个错误;我检查过的所有编译器都表现得如此)?
我该如何解决这个错误?所有以下修复工作,但我应该选择哪一个?
void print(class base1*pointer){}
void print(:: my :: base1*pointer){}
class base1; void print(base1*pointer){}
编辑:
int …Run Code Online (Sandbox Code Playgroud) 鉴于此示例代码:
#include <iostream>
#include <stdexcept>
class my_exception_t : std::exception
{
public:
explicit my_exception_t()
{ }
virtual const char* what() const throw()
{ return "Hello, world!"; }
};
int main()
{
try
{ throw my_exception_t(); }
catch (const std::exception& error)
{ std::cerr << "Exception: " << error.what() << std::endl; }
catch (...)
{ std::cerr << "Exception: unknown" << std::endl; }
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到以下输出:
Exception: unknown
Run Code Online (Sandbox Code Playgroud)
然而,简单地使继承my_exception_t的std::exception public,我得到下面的输出:
Exception: Hello, world!
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释为什么继承类型在这种情况下很重要吗?奖励积分作为标准中的参考.
c++ ×10
inheritance ×3
c++11 ×2
name-lookup ×2
shared-ptr ×2
casting ×1
exception ×1
private ×1
upcasting ×1
weak-ptr ×1