类成员数组的对象没有默认构造函数和删除复制导引器初始化 [英] Class member array of objects without default constructor and deleted copy contructors initialization

查看:172
本文介绍了类成员数组的对象没有默认构造函数和删除复制导引器初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个名为Container的类,其中必须存储类DontCopyMe的三个(在编译时已知)对象。 DontCopyMe类具有非默认构造函数和删除的拷贝构造函数。如何初始化Containter?

I have a class called 'Container' in which three (known at compile time) objects of class DontCopyMe must be stored. Class DontCopyMe has non-default constructor and deleted copy constructors. How can I initialize Containter?

示例代码:

#include <string>

class DontCopyMe
{
    public:
        DontCopyMe(const unsigned int SomeInt, const std::string & SomeString): SomeInt(SomeInt), SomeString(SomeString)
        {
        }
        DontCopyMe(const DontCopyMe &) = delete;
        DontCopyMe & operator = (const DontCopyMe &) = delete;
        DontCopyMe(DontCopyMe &&) = delete;
        DontCopyMe & operator = (DontCopyMe &&) = delete;

    private:
        const unsigned int SomeInt;
        const std::string SomeString;
};

class Container
{
    public:
        Container(): Array{{1, "A"}, {2, "B"}, {3, "C"}}
        {

        }

    private:
        DontCopyMe Array[3];
};

int main()
{
    Container C;
    return 0;
}



当然我会得到:

Of course I'm getting:

main.cpp: In constructor 'Container::Container()':                                                                                                                                                                                            
main.cpp:22:56: error: use of deleted function 'DontCopyMe::DontCopyMe(DontCopyMe&&)'                                                                                                                                                         
         Container(): Array{{1, "A"}, {2, "B"}, {3, "C"}}    


推荐答案

clang ++ 3.6.2 编译您的代码。 g ++ 5.2.0 不。

clang++ 3.6.2 compiles your code. g++ 5.2.0 does not.

根据此报告,这是g ++中的错误。

这是一个(讨厌的解决方法:使用 std :: aligned_storage placement new 和显式析构函数调用:

Here's a (nasty) workaround, for the moment: use std::aligned_storage, placement new and explicit destructor calls:

#include <type_traits>

class Container
{
    private:
        using Storage = typename std::aligned_storage
        <
            sizeof(DontCopyMe), 
            alignof(DontCopyMe)
        >::type;

    public:
        Container()
        {
            // Construct an instance of `DontCopyMe` in the memory
            // location starting at `&Array[0]`.
            new (&Array[0]) DontCopyMe{1, "A"};

            // ...
            new (&Array[1]) DontCopyMe{2, "B"};
            new (&Array[2]) DontCopyMe{3, "C"};

            // You can also (and should) use a for-loop.
        }  

        ~Container()
        {
            // Interpret the bytes at location `&Array[2]` as if
            // they were a `DontCopyMe` instance, then call the
            // `~DontCopyMe()` destructor on it.
            (reinterpret_cast<DontCopyMe*>(&Array[2]))->~DontCopyMe();

            // ...
            (reinterpret_cast<DontCopyMe*>(&Array[1]))->~DontCopyMe();
            (reinterpret_cast<DontCopyMe*>(&Array[0]))->~DontCopyMe();

            // You can also (and should) use a for-loop.
        }   

    private:
        Storage Array[3];
};

您必须为 Containers 正确清理对齐的存储。您可能想要将所有 aligned_storage 相关代码包含在辅助类中。

You'll have to implement move and copy operations for Containers that cleanup the aligned storage properly. You may want to wrap all aligned_storage-related code in an helper class.

你提到你需要更多的安全性和稳定性。实现这个的最好的方法是在一个帮助类中包装 std :: aligned_storage ,这将确保你不犯错误。

You mentioned you require additional safety and constness. The best way to achieve this is wrapping std::aligned_storage in an helper class that will make sure you don't make mistakes.

以下是一些让你开始使用的代码:

Here's some code to get you started:

#include <type_traits>
#include <utility>
#include <cassert>

template<typename T, std::size_t TSize>
struct ASImmutableArray
{
    private:
        using ThisType = ASImmutableArray<T, TSize>;

        using Storage = typename std::aligned_storage
        <
            sizeof(T),
            alignof(T)
        >::type;

        Storage data[TSize];

        template<typename... Ts>
        void initAt(std::size_t mIndex, Ts&&... mXs)
        {
            assert(mIndex >= 0 && mIndex < TSize);
            // assert the data was not initialized
            new (&data[mIndex]) T(std::forward<Ts>(mXs)...);
        }

        void deinitAt(std::size_t mIndex)
        {
            assert(mIndex >= 0 && mIndex < TSize);
            // assert the data was actually initialized
            reinterpret_cast<T*>(&data[mIndex])->~T();
        }

    public:
        // ...


};

一个想法是传递 std :: tuple ASImmutableArray 的构造函数中创建实例,并使用 placement new 创建 T code>通过扩展元组并将它们的内容转发到 T 的构造函数,以正确的索引。元组将包含与构建 T 所需的类型相同的类型。

An idea is passing std::tuple instances in the constructor of ASImmutableArray, and creating T instances in place using placement new at the correct indices by expanding the tuples and forwarding their contents to T's constructor. The tuples would contain the same types as the types required to construct T.

您还可以跟踪初始化/ deinitialized items with an additional member boolean array(可以在发布版本中禁用,只用于在开发过程中验证类的正确用法)。

You can also keep track of initialized/deinitialized items with an additional member boolean array (that can be disabled in release builds, and only used for verifying the correct usage of the class during development).

想要类似的(旧)实施的示例,这是我写的一个我的图书馆

If you want an example of an (old) implementation of something similar, this is something I've written for one of my libraries.

您还可以查看我写了这个标记的联合实现看到一个例子,我如何使用调试的成员变量没有额外的安全发行版本的开销。

You can also check out this tagged union implementation I've written to see an example on how I use debug-only member variables that have no overhead in release-builds for additional safety.

这篇关于类成员数组的对象没有默认构造函数和删除复制导引器初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆