我正在尝试在 C++ 中创建不可变类型(类),

我这样做是为了让所有方法“又名成员函数”不会修改对象并返回一个新实例。

我遇到了很多问题,但它们都围绕着 C++ 中的引用类型。

一个例子是通过引用传递相同类类型的参数时:

Imm Imm::someOp( const Imm& p_im ) const
{
   ...
   p_im = p_im.someOtherOp(); //error, p_im is const, can't modify it!
   ...
}

该错误是由引用传递值引起的。相反,如果我按值传递引用,那么上面的错误行就不会是错误!

考虑一个 Java/C# 示例

class Imm
{
    ...
    Imm someOp( Imm p_im )
    {
        ....
        p_im = p_im.someOtherOp(); //ok, you're not modifying the 
                 //original object, just changing the local reference
        ....  
    }
    ....
}

我怎样才能在 C++ 中做这样的事情?我知道我可以使用指针,但后来我遇到了整个内存管理混乱。我不想担心谁拥有对象的引用。

理想情况下,我想将类设计得像 python 中的不可变字符串;您可以使用它们,而无需注意甚至不知道它们是不可变的,并且它们的行为就像您所期望的那样;他们只是工作。

编辑

当然,我可以通过按值传递或使用临时变量(这就是我当前正在做的事情)来解决它。我要问的是“如何在 C++ 中按值传递引用”

我期待答案围绕 STL 中的某些内容,我目前正在研究 smart_ptr 系列模板。

更新

感谢您的回复,我意识到无法逃避指针。(参见我的 其他问题, ,这实际上是这个的后续)

有帮助吗?

解决方案

在Java和C#中,你并没有真正处理的参考 - 他们更像是句柄或指针。在C ++中的参考文献是真正的原始对象,而不是指向它的指针(尽管它可以用一个指针实现)的另一个名称。当你分配一个值的引用,你是指派对象本身。存在这样的困惑初始化,您可以使用=字符的参考,但它是一个初始化,不是赋值。

 Imm im, im2, im3; 
 Imm &imr = im;  // initialize a reference to im
 imr = im2; // assign im2 to imr (changes the value of im as well)
 Imm *imp = &im; // initialize a pointer to the address of im
 imp = &im3; // assign the address of im3 to imp (im is unnaffected);
 (*imp) = im2; // assign im2 to imp (modifies im3 as well).

如果你特别想通过“按值引用”,那么你基本上是要求在用词上矛盾性。引用,顾名思义是通过引用传递。正如其他地方所指出的,你可以通过值传递一个指针,否则直值。如果你真的想,你可以守住一类的引用和周围通过值:

 struct ImmRef
 {
     Imm &Ref;
     ImmRef(Imm &ref) : Ref(ref) {}
 };

还要注意的是一个const施加到参考正在使称为对象恒定,而不是参考。引用总是常量。

其他提示

时不分配,根据定义,不是一个常数操作?

您看起来像你想分配的东西const引用,这完全违背了一个const引用的想法。

我想你可能会寻找一个指针,而不是参考。

它不会像在C ++工作

当你传递一个参考到对象时,实际上是通过在地址中的对象的存储器。引用不能被重新安置到其他对象或者,因此C ++谚语“基准是对象”。你必须作出一个拷贝进行修改。 Java将做到这一点的场景,在你身后。 C ++,你只需要复制它。

你没忘记设置你打电话为const的方法?

编辑:所以,用const固定

也许你应该这样做。

Imm & tmp = p_im.someOtherOp();

然后执行进一步的操作上TMP变量。

如果您设置一个变量或参数为const&你就不能分配给它。

检查此项以了解临时生命周期 http://herbsutter.wordpress.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/

Imm Imm::someOp( const Imm& p_im ) const
{
   ...
   //Imm& im = p_im.someOtherOp();       // will *not* work
   const Imm& im = p_im.someOtherOp();   // will work, but you get a const reference
   ...
}

但你可以使用 boost::shared_ptr

shared_ptr<Imm> Imm::someOtherOp() const
{
  shared_ptr<Imm> ret = new Imm;
  ...
  return ret;
}

shared_ptr<Imm> Imm::someOp(const share_ptr<Imm>& p_im) const
{
  shared_ptr<Imm> im = p_im->someOtherOp();
}

您需要让你进入论证的新副本。你可以做你想做的事,相当于几个方面:1),你可以通过按值:

Imm Imm::someOp( Imm im ) const {
   im = im.someOtherOp();      // local im is a copy, original im not modified
   return im;                  // return by value (another copy)
}

或2),则可以通过按引用并作出明确的副本:

Imm Imm::someOp( const Imm & im ) const {
   Imm tmp = im.someOtherOp(); // local tmp is a copy
   return tmp;                 // return by value (another copy)
}

这两种形式是等价的。

C ++有一些比不变类型-const更好。单个类型可以是可变的,或不依赖于你的需求。这就是说,存在用于处理短寿命(近)拷贝有用的模式:

void f(const X &x) {
  // Trivial case: unconditional copy
  X x2=transform(x);
  // Less trivial: conditional copy
  std::optional<X> maybe;
  const X &use=need_copy ? maybe.emplace(transform(x)) : x;
  use.go();  // whichever, x or *maybe
}  // *maybe destroyed iff created, then x2 destroyed

std::unique_ptr可以以类似的方式之前,C ++ 17被使用,虽然功能可以那么当然掷std::bad_alloc

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top