简体   繁体   中英

Sharing an instance (of QList) between two classes in C++

Coming from C# to Qt I'm having trouble understanding how to properly translate the following common idiom (C#):

class Customer {
  public property List<Address> Addresses { get; }
}

class AnotherClass {
  public void SetAsShipping(List<Address> addresses) {
    foreach(var address in addresses)
      if (address.IsMatch(_shipping))
        address.IsShipping = true;    // This is the important part
  }
}

var cust = new Customer();
var another = new AnotherClass();

another.SetAsShipping(cust.Addresses);

I have the following C++:

class Customer {
  public:
    QList<Address> addresses() const { return _addresses; }
  private:
    QList<Address> _addresses;
};

class AnotherClass {
public:
  void setAsShipping(QList<Address> addresses);
};

AnotherClass::setAsShipping(QList<Address> addresses) {
  QList<Address>::iterator address;

  for (address = addresses->begin(); address != addresses->end(); ++address)
    if (address->isMatch(_shipping))
      address->setIsShipping(true);    // This is modifying a copy :(
}

Customer cust;
AnotherClass another;

another.setAsShipping(cust.addresses());

I know I could return _addresses as a reference and then pass it by reference, but apparently that can cause problems because my Customer instance could go out of scope before the reference to _addresses does and that will cause a "dangling reference". I found that much out from searching. What I didn't find was what one should do instead. Obviously there is a standard C++ way to do this sort of thing, but my brain is so stuck in managed code mode that it's not jumping out at me. How should I write this code so that the addresses list can be modified by AnotherClass?

In your C# Customer class, Addresses is just public property, you can do that as well in C++, but it's obviously not a good design.

class Customer {
  public:
     QList<Address> _addresses;
};

AnotherClass::setAsShipping(QList<Address>& addresses) {
  for (QList<Address>::iterator address = addresses->begin(); 
       address != addresses->end(); ++address)
  {    
    if (address->isMatch(_shipping)) {
      address->setIsShipping(true);    // Now modify the real object
    } 
  }
}

To do it in a better way, let's re-consider your C# design.

1.why is List<Address> Addresses public ?

2.Should SetAsShipping really belong to Another class? Looks like it belong to Customer class?

3.further enhancement, could use Qlist algorithms to find the address instead of for loop?

class Customer
{
public:
    void setAsShipping(const Address& address)
    {
        for (QList<Address>::iterator address = addresses->begin(); 
        address != addresses->end(); ++address)
        {    
            if (address->isMatch(_shipping)) {
                address->setIsShipping(true);    // Now modify the real object
            } 
        }
    }
private:
  QList<Address> _addresses;
};

customer cust;
AnotherClass another;

cust.setAsShipping(another.address()); 

Now is there still dangling reference concern?

也许您可以尝试返回QList对象副本,而不是将setAsShipping的返回类型保持为void

To have equivalent of C# property you have to change parameter of template ( QSharedPointer ):

class Customer : {
  public:
     QList<QSharedPointer<Address> > _addresses;
};

QSharedPointer is none intrusive reference counting pointer (this will simplify memory management). This way you can do modification on QList elements (this is what you need), but you are unable to change content of this QList (add/remove/replace elements) and still you have normal getter (returning a value not reference) for addresses.

so your problematic code will work like this:

AnotherClass::setAsShipping(const QList<Address> addresses) {
// here you have a copy of QList - it is copy on write pattern 
// so adding const will prevent from creating a copy of QList 

  Q_FOREACH (QSharedPointer<Address> address, addresses)
    if (address->isMatch(_shipping))
      address->setIsShipping(true);    // This will modify original value
}

You can use QSharedDataPointer (reference counting intrusive pointer - in this case Address has to extend QSharedData).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM