【问题标题】:C++ - call assignment operator at creation instead of copy constructorC++ - 在创建时调用赋值运算符而不是复制构造函数
【发布时间】:2011-04-13 19:56:06
【问题描述】:

我想强制在类似于原生类型的结构之间进行显式转换:

int i1;
i1 = some_float; // this generates a warning
i1 = int(some_float): // this is OK
int i3 = some_float; // this generates a warning

我想用赋值运算符和复制构造函数来做同样的事情,但行为不同:

Struct s1;
s1 = other_struct; // this calls the assignment operator which generates my warning
s1 = Struct(other_struct) // this calls the copy constructor to generate a new Struct and then passes that new instance to s1's assignment operator
Struct s3 = other_struct; // this calls the COPY CONSTRUCTOR and succeeds with no warning

有没有什么技巧可以让第三种情况Struct s3 = other_struct;用默认构造函数构造s3,然后调用赋值运算符?

这一切都按原样编译和运行。 C++ 的默认行为是在创建新实例时调用复制构造函数而不是赋值运算符并且立即调用复制构造函数(即MyStruct s = other_struct;成为MyStruct s(other_struct);而不是@987654326 @. 我只是想知道是否有任何技巧可以解决这个问题。

编辑:“显式”关键字正是我所需要的!

class foo {
    foo(const foo& f) { ... }
    explicit foo(const bar& b) { ... }
    foo& operator =(const foo& f) { ... }
};

foo f;
bar b;
foo f2 = f; // this works
foo f3 = b; // this doesn't, thanks to the explicit keyword!
foo f4 = foo(b); // this works - you're forced to do an "explicit conversion"

【问题讨论】:

  • 请发布一些精简版的真实代码。同时发布警告和错误。在我看来,您想做一些非常愚蠢的事情,而编译器正在告诉您。
  • @San Jacinto:我认为 Chris 想要以这样的方式编写类.
  • 等等,这个问题有没有根本性的改变?
  • @John:不,它没有。我只是措辞更好。

标签: c++ copy-constructor assignment-operator


【解决方案1】:

免责声明:我已准备好对此投反对票,因为这不能回答问题。但这可能对 OP 有用。

我认为将复制构造函数视为默认构造+赋值是一个非常糟糕的主意。反之亦然:

struct some_struct
{
    some_struct();  // If you want a default constructor, fine
    some_struct(some_struct const&); // Implement it in the most natural way
    some_struct(foo const&);         // Implement it in the most natural way

    void swap(some_struct&) throw(); // Implement it in the most efficient way

    // Google "copy and swap idiom" for this one
    some_struct& operator=(some_struct x) { x.swap(*this); return *this; }

    // Same idea
    some_struct& operator=(foo const& x)
    {
        some_struct tmp(x);
        tmp.swap(*this);
        return *this;
    }
};

以这种方式实现是万无一失的,并且在 C++ 中的转换语义方面是您可以获得的最好的,因此它是 的方式。

【讨论】:

    【解决方案2】:

    如果为 other_struct 重载类型转换运算符并相应地编辑原始结构,您可以解决此问题。也就是说,它非常混乱,通常没有充分的理由这样做。


    #include <iostream>
    
    using namespace std;
    
    struct bar;
    
    struct foo {
        explicit foo() {
            cout << "In foo default constructor." << endl;
        }
    
        explicit foo(bar const &) {
            cout << "In foo 'bar' contructor." << endl;
        }
    
        foo(foo const &) {
            cout << "In foo constructor." << endl;
        }
    
        foo const & operator=(bar const &) {
            cout << "In foo = operator." << endl;
            return *this;
        }
    };
    
    struct bar {
        operator foo() {
            cout << "In bar cast overload." << endl;
            foo x;
            x = *this;
            return x;
        }
    };
    
    int main() {
        bar b;
        foo f = b;
        return 0;
    }
    

    输出:

    In bar cast overload.
    In foo default constructor.
    In foo = operator.
    In foo constructor.
    In foo constructor.
    

    【讨论】:

    • 两次调用复制构造函数。
    • @Noah:我相信这是因为编译器在返回时无法优化从 cast 运算符创建的副本。
    • 也许吧。关键是它无法为 OP 提供他们想要的东西。当然,它确实在其中添加了对赋值运算符的调用,但它并没有改变 Type t = x 的本质。该变量仍然是使用复制构造函数构造的。您所做的只是在其中插入一个临时文件,该临时文件恰好是使用默认 + op= 创建的。
    • @Noah:它从不使用“bar”复制构造函数构造它——只是 foo 构造函数。它使用赋值运算符从 bar 复制它。
    • @Noah:正如上面 Chris 所说,它不会触及“bar”复制构造函数。 OP 希望通过首先使用默认构造函数然后使用赋值运算符来避免这种情况。它完全符合 OP 的要求。
    【解决方案3】:

    我不这么认为。当你写

    Struct s3 = other_struct;
    

    它看起来像一个赋值,但实际上它只是调用构造函数的声明性语法。

    【讨论】:

      【解决方案4】:

      简而言之,没有。

      长版本...实际上就是这样。这不是它的工作原理。不过必须想出一些东西来满足角色要求。

      【讨论】:

      • 可能的长版本:MyStruct s(other_struct)MyStruct s = other_struct 一样明显是一种转换。在这两种情况下,您都在代码行中声明了s 的类型,但没有声明other_struct 的类型。那么为什么它们与显式/隐式转换的 POV 有什么不同呢?事实上,他们不是。
      猜你喜欢
      • 1970-01-01
      • 2011-02-08
      • 2013-09-28
      • 2017-09-03
      • 2013-07-03
      • 1970-01-01
      • 2012-03-01
      • 1970-01-01
      • 2011-07-19
      相关资源
      最近更新 更多