Exchange an object by reference or pointer

Say I have an object of type A that has an Initialize () method. The method receives object B, which is stored as a member of the object's data. B is shared between several objects, so A must contain the originally received object of B, and not a copy of it.

class A { public: bool Initialize(B?? b); private: B?? m_B; } 

An object B must be present. So, I think, to pass it by reference, instead of passing a pointer and not initializing () in the case when B is NULL.

The only algorithm for m_B should be the type of pointer B (it cannot be a reference to B, since the initialization of B is not performed in c-tor). Thus, the initialization should look like this:

 bool A::Initialize(B& b) { m_B = &b; .... } 

Is this aproach okay?

UPD:

  • The code is not new, and I'm just trying to β€œfix” some problems. In fact, I'm not talking about some specific classes A and b, but rather about how the problem approaches my code base. The code passes a pointer to B widely and checks it in Initialize () if it is NULL.

  • Passing B to C-tor is not always a good option. There are also other parameters passed to A that do not exist at the time of creating A. Therefore, I do not want to pass some of the Ac-tor parameters, and the rest to A :: Initialize ().

  • shared_ptr can also be "NULL", so passing it to A :: Initialize () is no different than passing only a pointer to B, in the aspect that the signature Initialize () does not declare if B is mandatory or not. In my case, this is the case, and I want to express it by passing a link to B.

  • Our code currently does not use boost. So, although the shared_ptr solution is better than just passing the raw pointer, can the solution I propose be considered a bad, but still a solution.

+1
source share
6 answers

I would stay with a pointer. The link here just sends the wrong message.

You do not use object references in situations when you plan to use a pointer to an object to store and share it, etc. The main reason for C ++ references allows things like operator overloading and copying constructors to work with user-defined types. Without them, it would be difficult to provide this functionality with syntax that does not differ from built-in types.

But in this situation, you are not trying to mimic the built-in type. You work on an object that is commonly used with a pointer and even shared several different pointers. So be honest with that.

For b , which is NULL, be sure to use assert(b) (or a similar construct) to enforce the contract and terminate the invalid program. (I would not choose an exception. Even if you forget about problems with exceptions in C ++, do you plan to ever catch and handle such an exception in your code?) I would also add such statements to the whole code that m_B uses in the case of if someone forgot to call A::Initialize() .

Using a reference to ensure that the pointer is not null can skip gaps. In most implementations, you can make a reference from NULL or a dangling pointer without any errors. Your application will fail only if you try to use this link. Therefore, if someone accidentally gives you B *pb equal to NULL, you can call pa->Initialize(*pb) and nothing happens. Except pa->m_B now NULL.

Whether to use something like boost::shared_ptr up to you and your memory management strategy. This is a completely unrelated issue.

+1
source

If B is optional, it can be represented as a pointer. If B is required, then it should be presented as a reference.

If possible, try to avoid the β€œtwo-stage design” using the initialization method. If this is not possible, then inside A you need to consider B as optional and store it as a pointer and test, wherever you want to use it.

If your initialization method (or, ideally, a constructor) requires B, you should pass it as a reference.

All of this assumes that you know who actually owns B; perhaps B owns the instances of A and initializes them with references to itself, or perhaps B belongs to what also belongs to all instances of A that refer to this instance of B.

If the objects A of your own B are shared, you should use something like boost :: shared_ptr to make shared ownership explicit; assuming B is dynamically allocated by the new.

+2
source

Passing B as a reference, the lifetime of B is longer than the lifetime (or de-initialization time) A. If so, you must go through an oversupply. Internally, you can also save the link in a Boost reference wrapper (but this is Boost, so maybe this is not an option).

If you pass pointers, and you are sure that they should never be NULL if your program is correct, then use statements and if-clause to check this.

I also sometimes have a script that you desrcibe and usually use your proposed solution. This is the easiest.

Depending on the complexity and design of your classes, you can also use a variation of the state template where the state object that describes the "initialized" -state is built in the initialize method. In this case, you can pass a reference to the constructor of the state object. This is probably an excess (the C ++ state model has a significant boiler plate, so make sure it's worth it) and requires a lot of refactoring, but maybe it will help you in some way.

+1
source

I would go with boost :: shared_ptr. If you use links, you may need to worry about the size of the referent; if you use a simple pointer, you get into memory management problems. Who is going to remove B?

Perhaps just think about your circuit one more time: do you really need to split the object or make a copy of ctor for type B enough? If B will be changed by other classes, and these changes should be known to other classes, you will need shared_ptr.

0
source

I believe that you should use the constructor instead of using the Initialize method.

Passing B to c-tor is not always a good option either. There are other parameters passed to A that do not exist at the time of creation of A. Therefore, I woudln't prefer to pass some parameters to A c-tor, and the rest is A :: Initialize ().

Have you heard about predesign?

Here is an example of what you could do:

 class IsEmpty{}; class A { B *b_; int *c_; char *d_; void Initialize(B *b) { b_ = b; c_ = b_->Getc(); d_ = b_->Getd(); } public: A(B *b) : b_(0), c_(0), d_(0) { if(b == 0) throw IsEmpty(); Initialize(b); } }; 
0
source

I would definitely avoid using the link as a member of the class, if at all possible. There are a million ways it can hurt you. If you do, you should use a list of initializers, but this is another function that you should avoid, like the plague. It works great for simple cases, but can cause serious problems.

0
source

Source: https://habr.com/ru/post/954083/


All Articles