哪一个更好:谎言副本构造函数还是非标准构造函数? 我有一个C++类,包含一个不可复制的句柄。但是,该类必须具有副本构造函数。因此,我实现了一个将句柄的所有权转移到新对象的方法(如下所示)

哪一个更好:谎言副本构造函数还是非标准构造函数? 我有一个C++类,包含一个不可复制的句柄。但是,该类必须具有副本构造函数。因此,我实现了一个将句柄的所有权转移到新对象的方法(如下所示),c++,C++,我的问题是,标准副本构造函数接受常量引用,我正在修改该引用。因此,我想知道哪个更好(以及为什么): 非标准副本构造函数: Foo(Foo&other) “存在”的复制构造函数: Foo(const Foo&other) 编辑: DuplicateHandle()仅适用于特定类型的句柄。这不是其中之一。无法复制、复制或克隆此句柄 有几个人指出,我错误地认为它是一个非标准的复制构造函数,而std::auto_ptr就是这样做的。我想这可能是最好的办法。但是,每次使用该类时,当我使copy-ctor

我的问题是,标准副本构造函数接受常量引用,我正在修改该引用。因此,我想知道哪个更好(以及为什么):

  • 非标准副本构造函数:
    Foo(Foo&other)

  • “存在”的复制构造函数:
    Foo(const Foo&other)


  • 编辑:

    DuplicateHandle()
    仅适用于特定类型的句柄。这不是其中之一。无法复制、复制或克隆此句柄

    有几个人指出,我错误地认为它是一个非标准的复制构造函数,而
    std::auto_ptr
    就是这样做的。我想这可能是最好的办法。但是,每次使用该类时,当我使copy-ctor采用非常量值时,都会得到警告。例如:

    namespace detail {
        class Foo { ... };
    };
    
    class Buzz
    {
    public:
        typedef detail::Foo Fuzz;
    
        Fuzz bar() const { return Fuzz(); }; // warning here
    };
    
    warning C4239: nonstandard extension used : 'argument' : conversion from 'Foo' to 'Foo &'
    1> A non-const reference may only be bound to an lvalue; copy constructor takes a reference to non-const
    
    有人能建议我该怎么办吗


    编辑2:

    每个人似乎都在引导我朝着std::auto_ptr
    的做事方法前进。所以,我看了一下,它使用了一个中间结构来绕过我在第一次编辑中描述的问题。这就是我想出的解决办法

    class Foo;
    
    struct Foo_ref
    {
        explicit Foo_ref( Foo& other ) : ref_( other ) {};
        Foo& ref_;
    private:
        const Foo_ref& operator=( const Foo_ref& );
    }; // struct Foo_ref
    
    class Foo
    {
    public:
        Foo() : h_( INVALID_HANDLE_VALUE )
        {
        };
    
        // transfer the handle to the new instance
        Foo( Foo_ref other ) : h_( other.ref_.Detach() )
        {
        };
    
        ~Foo()
        {
            if( INVALID_HANDLE_VALUE != h_ )
                CloseHandle( h_ );
        };
    
        operator Foo_ref()
        {
            Foo_ref tmp( *this );
            return tmp;
        };
    
        // other interesting functions...
    
    private:
    
        /// disallow assignment
        const Foo& operator=( const Foo& );
    
        HANDLE Detach()
        {
            HANDLE h = h_;
            h_ = INVALID_HANDLE_VALUE;
            return h;
        };
    
        /// a non-copyable handle
        HANDLE h_;
    }; // class Foo
    

    它在警告级别4上编译得很干净,似乎可以工作。请告诉我,这是否比我原来的帖子更不负责任。

    第一个选项有一个很好的先例,即
    自动ptr

    auto_ptr
    放弃指针并在复制时重置

    确保函数不改变作为const传递的参数的标准要比copy-ctor标准强得多,后者实际上不是很正式


    此外,根据标准,通过丢弃常量值来操纵常量值是未定义的行为。如果您确定引用引用了一个非常量对象,或者您正在将一个常量对象传递给一个不会修改该值的(const-increct)函数,则可以这样做。

    我肯定不会像您在这里一样实现复制构造函数。Detach方法声明为const,但实际上不是。最好使复制构造函数遵循标准表单,但使其私有和/或在调用时抛出。然后,您可以提供复制句柄和任何其他适用属性的克隆方法。

    这很简单:非标准方法。修改const参数的构造函数很难被开发人员预测。您需要将其记录下来,开发人员需要知道如何查看文档以获得非常常见的用途……这是大多数人不会做的

    然而,一个非标准的构造函数值得注意


    此外,这是标准如何使用auto_ptr实现的。为什么?所以你不能不小心把它放在一个容器里。使用非标准版本的另一个很好的理由。

    您的班级基本上在做std:;自动ptr可以。auto_ptr的复制构造函数如下所示:

    auto_ptr( auto_ptr & p );
    

    这意味着它不能在某些情况下使用,比如在标准容器中。这可能是最佳实践,但值得注意的是,auto_ptr在C++0x中已被弃用。

    也许复制构造函数应该只用于制作真正的副本。

    如果您确实需要复制构造函数,那么您必须确保它具有正确的语义。如果你实施了你的任何一种方法,那么你就是在自找麻烦。依赖于复制构造函数的代码将不知道所有权转移方案,这可能会产生不可预测的结果。(例如,这就是不能在STL容器中使用std::auto_ptr的原因。)

    如果您真的不需要复制构造函数,那么创建一个复制对象并转移句柄所有权的方法

    如果确实需要副本构造函数,那么需要一种在副本之间共享句柄的方法。我建议使用auxiallary对象来存储句柄和引用计数,以便知道何时关闭句柄。我还要重新检查你关于句柄不可复制的假设。如果唯一的问题是必须只关闭它一次,那么可以使用DuplicateHandle()函数解决该问题


    最后一句话:我要说,编程中的一个基本原则是,不要对函数做什么撒谎。也许,

    < P>,对于一个不可复制的对象,而不是使用非标准或WiRD复制构造函数,你应该考虑不复制它。您可以使用新的共享\u ptr机制或独特的\u ptr进行所有权移交,而不用自己担心这些事情

    使用非
    常量
    复制构造函数是很好的。我不知道你为什么叫它“非标准”。该标准明确规定(§12.8/2)复制构造函数参数不必是
    const
    。通常是这样,因为修改另一个对象几乎没有必要,并且有其缺点(例如,不能在标准容器中使用)

    但我宁愿重新审视设计:你真的需要复制一个明显不可复制的对象吗?语义学则相反。或者,您不能以安全的方式复制底层句柄吗

    • 或者只分配它并使用共享所有权语义,或者与引用计数器一起使用,这样就不会关闭句柄两次,或者太早
    • 或者导致句柄的基础对象被复制

      • 两者都很可怕。如果您的类具有不可复制的成员变量,则您的类是不可复制的

        如果让您的类不可复制确实是不可接受的,一种解决方法是使用指向“状态”类/结构的共享指针来存储不可复制的对象(它本身是不可复制的),但是
        auto_ptr( auto_ptr & p );
        
        Fuzz bar() const { Fuzz fuzz; return fuzz; };