Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/magento/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使类成员保持未构造状态,以便以后使用新放置进行构造_C++_Constructor_Initialization_C++14 - Fatal编程技术网

C++ 如何使类成员保持未构造状态,以便以后使用新放置进行构造

C++ 如何使类成员保持未构造状态,以便以后使用新放置进行构造,c++,constructor,initialization,c++14,C++,Constructor,Initialization,C++14,我想制作一个包含私有成员的模板,在使用placement new显式构造之前,该模板应保持未构造状态 如何使用C++14实现这一点 有点像这样: template <typename T> class Container { private: T member; //should be left unconstructed until construct() is called public: Container() = default

我想制作一个包含私有成员的模板,在使用placement new显式构造之前,该模板应保持未构造状态

如何使用C++14实现这一点

有点像这样:

template <typename T>
class Container {
    private:
        T member; //should be left unconstructed until construct() is called
    public:
        Container() = default;
        void construct() {
            new (&this->member) T();
        }
};
模板
类容器{
私人:
T member;//在调用construct()之前应保持未构造状态
公众:
容器()=默认值;
void构造(){
新建(&this->member)T();
}
};
需要注意的一点是,当您继续实现时,您将开始看到这种方法的一些缺点(以其最简单的形式)。当然,你必须有一个布尔值,来检查东西是否已经被构造,等等。因此,您将使用析构函数、复制、移动运算符来检查布尔值,然后执行某些操作

但是,如果所包含的类型本身是平凡的,例如整数或其他类型,则不需要这些。在某些情况下,这会对性能造成很大影响。因此,标准要求这些特性从包含的类型传递到可选类型。也就是说,如果包含的类型是可破坏的,那么该类型上的可选类型也是可破坏的。因此:

std::cerr << std::is_trivially_destructible_v<std::optional<int>>;

std::cerr有一种比Nir更干净的方法,使用类似于union的类:

template <typename T>
class Container {
    private:
        bool is_constructed = false;
        union { T member; };
    public:
        Container() {}
        ~Container() {
            if (is_constructed) {
                member.~T();
            }
        }
        void construct() {
            assert(!is_constructed);
            new (&this->member) T();
            is_constructed = true;
        }
};
模板
类容器{
私人:
bool是_构造的=false;
工会{T成员;};
公众:
容器(){}
~Container(){
如果(是否构造){
成员~T();
}
}
void构造(){
断言(!已构造);
新建(&this->member)T();
is_constructed=true;
}
};

您可能还需要添加其他构造函数/赋值运算符。当然,在这个简单的例子中,
std::optional
做了完全相同的事情,但更干净。如果您想避免
bool
的开销,例如如果
是构造的,则可以在其他状态下对其进行编码,或者如果有多个成员受同一标志控制,则这仍然很有用。

类构造是一个全有或全无的命题。要么构造整个类,要么什么都不构造。没有中间立场。你想解决的真正问题是什么。不,不是关于不构造类成员的问题,而是你认为其解决方案涉及不构造单个类成员的问题。@SamVarshavchik实现std::Optional我讨厌这样说,但是<代码>malloc
。请参阅:使用非公共的
std::aligned_storage
reinterpret_cast
ing getter/setter。更好的是,将其包装到另一个类中,添加双重构造/破坏保护。
std::optional
不作为类成员实现。它是通过声明一个
char
数组
sizeof(T)
实现的,该数组是类成员,然后使用placement new构造它。你的类成员不是T,而是一个
char
数组。我不知道是谁否决了这个,但我猜是因为如果
construct
被调用两次,它将是UB。需要一个布尔标志,如果它已被构造,我想。是的。。。。我假设您要解决可选实现的其他部分,只需要这方面的帮助。投票人是否希望我在回答中实现所有可选选项?我会尽快接受这个答案(10分钟后)。添加布尔标志会很好,因为它可以避免其他人在寻找布尔标志时忽略以下事实:调用两次
construct
将是UB。这不是我的否决票,但您使用的
aligned_存储是完全错误的。“将在大多数标准库实现中打印出1。”我希望它能在所有标准库实现中打印1,因为它是……哇,我从来没有想过使用联合,但现在我看到它非常简单和直接。@FSMaxB实际上不是。您只需了解涉及非平凡类型的联合的所有规则即可。由于这基本上从未出现过,我宁愿坚持使用新的和对齐的存储。另外,关于避免“bool”开销的评论也有点离谱,不管你是这样做的,都是100%正交于union还是aligned_存储。@NirFriedman我确实不太理解关于避免bool开销的评论。这真的没有道理。来自C语言背景,使用联合体对我来说是有意义的。但是现在我想起来,仅仅构造联合成员甚至可能是未定义的行为。@Nirfiedman我的意思是与
std::optional
struct X{std::optional a,b,c;}
vs
struct Y{union{ta;};union{tb;};union{tc;};bool has_a:1;bool has_b:1;bool has_c:1;}。对于任何
T
sizeof(Y)
@FSMaxB,它都有很好的定义。否则,非POD类型的联合将毫无用处。
std::cerr << std::is_trivially_destructible_v<std::optional<int>>;
template <typename T>
class Container {
    private:
        bool is_constructed = false;
        union { T member; };
    public:
        Container() {}
        ~Container() {
            if (is_constructed) {
                member.~T();
            }
        }
        void construct() {
            assert(!is_constructed);
            new (&this->member) T();
            is_constructed = true;
        }
};