如何在 C++ 中按值传递引用?

发布于 2024-07-14 15:33:44 字数 1163 浏览 7 评论 0原文

我正在尝试在 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 系列模板。

更新

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

I'm trying to create am immutable type (class) in C++,

I made it so that all methods "aka member functions" don't modify the object and return a new instance instead.

I'm running across a bunch of issues, but they all revolve around the reference types in C++.

One example is when passing parameters of the same class type by reference:

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

The error is caused by passing the value by reference.
If instead, I was passing the reference by value, then the error line above would not be an error!

Consider a Java/C# example

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
        ....  
    }
    ....
}

How can I do something like this in C++? I know I can use pointers but then I run into the whole memory management mess. I don't want to worry about who owns references to objects.

Ideally I'd like to design the class to be like immutable strings in python; you can use them without ever noticing or even knowing that they're immutable, and they just behave as you expect; they just work.

EDIT

Of course I can get around it by passing-by-value or by using a temp variable (which is what I'm doing currently). What I'm asking about is "how to pass references by value in C++"

I'm expecting the answer to revolve around something in the STL, I'm currently looking into smart_ptr family of templates.

UPDATE

Thanks for the responses, I realize there's no escape from pointers. (see my other question, which is really a follow up on this one)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

勿挽旧人 2024-07-21 15:33:44

在 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。

In Java and C#, you are not really dealing with a reference - they are more like handles or pointers. A reference in C++ is really another name for the original object, not a pointer to it (although it may be implemented with a pointer). When you assign a value to a reference, you are assigning to the object itself. There is confusion in that to initialize a reference you can use the = character, but it is an initialization, not an assignment.

 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).

If you specifically want to pass "references by value" then you are essentially asking for a contradition in terms. References, by definition are passed by reference. As pointed out elsewhere, you can pass a pointer by value, or else a straight value. If you really want, you can hold onto a reference in a class and pass that around by value:

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

Note also that a const applied to a reference is making the referred to object constant, not the reference. References are always const.

灼疼热情 2024-07-21 15:33:44

根据定义,赋值不是一个常量操作吗?

您看起来像是在尝试将某些内容分配给 const 引用,这完全违背了 const 引用的想法。

我认为您可能正在寻找指针而不是引用。

Isn't assignment, by definition, not a constant operation?

You look like you're trying to assign something to a const reference, which totally defeats the idea of a const reference.

I think you may be looking for a pointer instead of a reference.

素手挽清风 2024-07-21 15:33:44

它不像 C++ 那样工作。

当你传递一个对象的引用时,你实际上传递的是该对象在内存中的地址。 引用也不能重新定位到其他对象,因此 C++ 谚语“引用就是对象”。 您必须复制一份才能修改它。 Java 会在幕后为您完成此操作。 C++,你只需复制它即可。

It doesn't work like that in C++.

When you pass a reference to an object, you are actually passing the address in memory of the object. References can't be re-seated to other objects either, hence the C++ adage "the reference IS the object." You HAVE to make a copy to modify it. Java will do this behind the scenes for you. C++, you just have to copy it.

笑看君怀她人 2024-07-21 15:33:44

你没有忘记将你调用的方法设置为const吗?

编辑:所以,const 固定。

也许您应该执行类似“

Imm & tmp = p_im.someOtherOp();

然后对 tmp 变量进行进一步操作”的操作。

如果将变量或参数设置为 const & 你只是不能分配给它。

Didn't you forget to set the method you call as const?

EDIT: so, with the const fixed.

Maybe you should do something like

Imm & tmp = p_im.someOtherOp();

Then do further operation on the tmp variable.

If you set a variable or a parameter as const & you just cannot assign to it.

终难愈 2024-07-21 15:33:44

检查此内容以了解临时生命周期 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();
}

Check this to know about temporary lifetime 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
   ...
}

But you can use 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();
}
︶葆Ⅱㄣ 2024-07-21 15:33:44

您需要为传入的参数制作一个新副本。 您可以通过几种等效的方式执行您想要的操作: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)
}

两种形式是等效的。

You need to make a new copy of your incoming argument. You can do what you want in several equivalent ways: 1) you could pass-by-value:

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)
}

or 2) you can pass-by-reference and make a copy explicitly:

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

both forms are equivalent.

无法回应 2024-07-21 15:33:44

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

C++ has something better than immutable types—const. A single type can be mutable or not depending on your needs. That said, there are useful patterns for dealing with short-lifetime (near-)copies:

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 may be used in a similar fashion prior to C++17, although the function can then of course throw std::bad_alloc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文