美文网首页
C++ 干货(持续添加)

C++ 干货(持续添加)

作者: 赛非斯 | 来源:发表于2022-03-30 23:04 被阅读0次

疫情在家,闲来无事,整理下零碎的知识点,备忘
1、const & 函数参数的用途
有时候为了追求效率,又希望避免改变原来的str,则可在引用的基础上加const修饰,这样函数中就不能再修改str的内容(否则会编译出错)
2、decltype
有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(初始化可以用auto)。为了满足这一需求,C++11新标准引入了decltype类型说明符,它的作用是选择并返回操作数的数据类型,在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值
3、callRemote 对remote()->transact的封装,简化了代码

  // callRemote is used to invoke a synchronous procedure call over Binder
    template <typename Method, typename TagType, typename... Args>
    status_t callRemote(TagType tag, Args&&... args) const {
        static_assert(sizeof(TagType) <= sizeof(uint32_t), "Tag must fit inside uint32_t");

        // Verify that the arguments are compatible with the parameters
        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
        static_assert(ArgsMatchParams<std::tuple<Args...>, ParamTuple>::value,
                      "Invalid argument type");

        // Write the input arguments to the data Parcel
        Parcel data;
        data.writeInterfaceToken(this->getInterfaceDescriptor());

        status_t error = writeInputs(&data, std::forward<Args>(args)...);
        if (CC_UNLIKELY(error != NO_ERROR)) {
            // A message will have been logged by writeInputs
            return error;
        }

        // Send the data Parcel to the remote and retrieve the reply parcel
        Parcel reply;
        error = this->remote()->transact(static_cast<uint32_t>(tag), data, &reply);

4、callLocal :Call the local method

    template <typename Method>
    status_t callLocal(const Parcel& data, Parcel* reply, Method method) {
        CHECK_INTERFACE(this, data, reply);

        // Since we need to both pass inputs into the call as well as retrieve outputs, we create a
        // "raw" tuple, where the inputs are interleaved with actual, non-pointer versions of the
        // outputs. When we ultimately call into the method, we will pass the addresses of the
        // output arguments instead of their tuple members directly, but the storage will live in
        // the tuple.
        using ParamTuple = typename SafeInterface::ParamExtractor<Method>::ParamTuple;
        typename RawConverter<std::tuple<>, ParamTuple>::type rawArgs{};

        // Read the inputs from the data Parcel into the argument tuple
        status_t error = InputReader<ParamTuple>{mLogTag}.readInputs(data, &rawArgs);
        if (CC_UNLIKELY(error != NO_ERROR)) {
            // A message will have been logged by read
            return error;
        }

        // Call the local method
        status_t result = MethodCaller<ParamTuple>::call(this, method, &rawArgs);

5、IMPLEMENT_META_INTERFACE 系统帮你生成aidl代码,有个很重要的方法asInterface 表示本地调用还是跨进程远程调用

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
    const ::android::String16&                                          \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != nullptr) {                                           \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == nullptr) {                                      \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    std::unique_ptr<I##INTERFACE> I##INTERFACE::default_impl;           \
    bool I##INTERFACE::setDefaultImpl(std::unique_ptr<I##INTERFACE> impl)\
    {                                                                   \
        if (!I##INTERFACE::default_impl && impl) {                      \
            I##INTERFACE::default_impl = std::move(impl);               \
            return true;                                                \
        }                                                               \
        return false;                                                   \
    }                                                                   \
    const std::unique_ptr<I##INTERFACE>& I##INTERFACE::getDefaultImpl() \
    {                                                                   \
        return I##INTERFACE::default_impl;                              \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }   

6、DECLARE_META_INTERFACE 相当于头文件定义

#define DECLARE_META_INTERFACE(INTERFACE)                               \
public:                                                                 \
    static const ::android::String16 descriptor;                        \
    static ::android::sp<I##INTERFACE> asInterface(                     \
            const ::android::sp<::android::IBinder>& obj);              \
    virtual const ::android::String16& getInterfaceDescriptor() const;  \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \
    static bool setDefaultImpl(std::unique_ptr<I##INTERFACE> impl);     \
    static const std::unique_ptr<I##INTERFACE>& getDefaultImpl();       \
private:                                                                \
    static std::unique_ptr<I##INTERFACE> default_impl;                  \
public: 

7、C++ template 模板定义
模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。C++ 的标准库提供许多有用的函数大多结合了模板的观念

8、writeStrongBinder 把binder对象序列化然后通过binder发送,下面是源码中序列化的方法
这里也区分了要序列化的binder是本地的还是远程的
BBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();

status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
        /* minimum priority for all nodes is nice 0 */
        obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
    } else {
        /* minimum priority for all nodes is MAX_NICE(19) */
        obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    }

    if (binder != nullptr) {
        BBinder *local = binder->localBinder();
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == nullptr) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.hdr.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {
            if (local->isRequestingSid()) {
                obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
            }
            obj.hdr.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {
        obj.hdr.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }

    return finish_flatten_binder(binder, obj, out);
}

9、std::function是一个函数包装器模板,说明了函数的返回值和函数参数类型,比如下面的定义和赋值
int fool(int x, int y)
{
return x+y;
}
std::function<int(int,int)> func = fool;
10、MemroyHeapBase也是Android搞的一套基于binder和共享内存机制的对内存操作的类,看如下代码,是通过ashmem_create_region 创建一块共享区域,class MemoryHeapBase : public virtual BnMemoryHeap 也就是服务端。MemoryBase 是对MemroyHeapBase进一步的封装,方便用户操作这块区域。IMemory,IMemoryHeap都是在binder上使用的,用于进程间内存共享的操作,用于在binder上传输大内存块的操作。因为parcel提供的共享内存块大小有限,并来回地复制,效率太低。故引入这两个接口来高效实现内存共享(传输) ,详细了解可以看看这篇英文文章[转载]Binder之 IMemory理解01 -- Share memory u_superman_新浪博客 (sina.com.cn)

MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
      mDevice(nullptr), mNeedUnmap(false), mOffset(0)
{
    const size_t pagesize = getpagesize();
    size = ((size + pagesize-1) & ~(pagesize-1));
    int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
    ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
    if (fd >= 0) {
        if (mapfd(fd, size) == NO_ERROR) {
            if (flags & READ_ONLY) {
                ashmem_set_prot_region(fd, PROT_READ);
            }
        }
    }
}

11、publishAndJoinThreadPool native 服务的发布方式,BinderService已经帮我们封装好了,非常实用

class BinderService
{
public:
    static status_t publish(bool allowIsolated = false,
                            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
                              dumpFlags);
    }

    static void publishAndJoinThreadPool(
            bool allowIsolated = false,
            int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
        publish(allowIsolated, dumpFlags);
        joinThreadPool();
    }

    static void instantiate() { publish(); }

    static status_t shutdown() { return NO_ERROR; }

private:
    static void joinThreadPool() {
        sp<ProcessState> ps(ProcessState::self());
        ps->startThreadPool();
        ps->giveThreadPoolName();
        IPCThreadState::self()->joinThreadPool();
    }
};

12、虚函数、纯虚函数、重写、继承

  1. 公有继承

纯虚函数 => 继承的是:接口 (interface)

普通虚函数 => 继承的是:接口 + 缺省实现 (default implementation)

非虚成员函数 =>继承的是:接口 + 强制实现 (mandatory implementation)

  1. 不要重新定义一个继承自基类的非虚函数 (never redefine an inherited non-virtual function)

  2. 在声明需要重写的函数后,加关键字 override

13、C++ override 虚析构函数 使用技巧
C++11 新特性中的关键字override,会检查基类中的虚函数和派生类中带有override的虚函数有没有相同的函数签名,一旦不匹配便会报错
因此子类设计者可以在其析构函数后增加关键字override,一旦父类缺少关键字virtual就会被编译器发现并报错

14、虚函数和纯虚函数
(1)、定义一个函数为虚函数,不代表函数为不被实现的函数。
(2)、定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
(3)、定义一个函数为纯虚函数,才代表函数没有被实现。
(4)、定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。
(5)、一般而言纯虚函数的函数体是缺省的,但是也可以给出纯虚函数的函数体(此时纯虚函数仍然为纯虚函数,对应的类仍然为抽象类,还是不能实例化对象)调用纯虚函数的方法为:抽象类类名::纯虚函数名(实参表)
引用:https://blog.csdn.net/qq_41306849/article/details/112531089

15、结构体指针转换

include <iostream>

using namespace std;
struct sc1{
int a;
};
struct sc2{
struct sc1 base;
int b;
};

void transform(struct sc1 *p){
struct sc2 *scp2= (struct sc2 *) p;
printf("test b =%d",scp2->b);
}
//把子结构体指针强转成父结构体指针,仍然能获取之前设置过的父结构体的其他数据
int main(){
struct sc2 scp2 = new sc2;
scp2->b=1;
transform(&scp2->base);
return 0;
}
类似void
作为参数,因为结构体是连续存放的
https://blog.csdn.net/sugelapeng/article/details/107127953

相关文章

网友评论

      本文标题:C++ 干货(持续添加)

      本文链接:https://www.haomeiwen.com/subject/qvvndrtx.html