唯一指针和常量正确性



我没想到会编译以下代码:

#include <iostream>
#include <memory>
class A
{
public:
    inline int get() const
    {
        return m_i;
    }
    inline void set(const int & i)
    {
        m_i = i;
    }
private:
    int m_i;
};
int main()
{
    const auto ptr = std::make_unique< A >();
    ptr->set( 666 ); // I do not like this line    D:<
    std::cout << ptr->get( ) << std::endl;
    return 0;
}

如果ptr是一个原始的C指针,我可以接受。但由于我使用的是智能指针,我不明白这背后的原理是什么。

我使用唯一指针来表示所有权,在面向对象编程中,这可以被视为对象组合("关系的一部分")。

例如:

class Car
{
    /** Engine built through some creational OO Pattern, 
        therefore it has to be a pointer-accessed heap allocated object **/
    std::unique_ptr< Engine > m_engine;
};

或者:

class A
{
    class Impl;
    std::unique_ptr< A::Impl > m_impl; // PIMPL idiom
};

如果类Car的实例是常量,为什么Engine不应该也是常量?如果它是一个共享指针,我会完全接受的。

有没有一个聪明的指针可以反映我想要的行为?

很简单:

const auto ptr = std::make_unique< A >();

这意味着指针本身是常量!但它所持有的对象并非如此。你可以看到它以另一种方式工作。。。

A *const ptr = new A();

这是一样的。指针是常量(不能修改为指向其他位置),但对象不是。

现在,你的意思可能是你想要这样的东西,不是吗?

const auto ptr = std::make_unique<const A>();

这将创建一个指向常量A的常量指针。

还有另一种方式。。。

auto ptr = std::make_unique<const A>();

对象是常量,但不是指针。

BTW:您所说的"常量传播"也适用于C++,与您所说相同。

尽管这是一个迟来的答案,但有一个解决方案可以在类中传播常量。

std::实验::propagate_const:

std::experimental::propagate_const是指针和类指针对象的const传播包装器。当通过const访问路径访问时,它将封装的指针视为指向const的指针,因此得名。

#include <iostream>
#include <memory>
#include <experimental/propagate_const>
class Car
{
    
    public:
        void start();
        void start() const;
    
    private:
        struct Engine;
        std::experimental::propagate_const<std::unique_ptr<Engine>> m_engine;
};

struct Car::Engine{
    void start(){
        std::cout<< "Engine started (non const)"<<std::endl;
    }
    
    void start() const{
        std::cout<<"Engine started (const)" <<std::endl;
    }
};
void Car::start(){
    m_engine->start();
    std::cout<< "Car started (non const)"<<std::endl;
}
void Car::start() const{
    m_engine->start();
    std::cout<< "Car started (const)"<<std::endl;
}

int main()
{
    Car c1;
    c1.start();
    
    const Car c2;
    c2.start();
    
    return 0;
}

o/p:

Engine started (non const)
Car started (non const)
Engine started (const)
Car started (const)

演示

最新更新