Skip to content

[IMPROVEMENT] reduce use of shared_ptr in the core #994

Open
@TonyXiang8787

Description

@TonyXiang8787

Background

In the PGM core we use std::shared_ptr in many places. Sometimes the usage is justified, but also at many places, the usage is not justified.

Shared ownership

std::shared_ptr is meant to be used for shared ownership. That is, there are multiple owners of the same resources, and we as library developer cannot determine in run-time which owner will be destroyed first. An example is shown below:

// calculation parameters
std::shared_ptr<ComponentTopology const> comp_topo;
std::vector<std::shared_ptr<MathModelTopology const>> math_topology;
std::shared_ptr<TopologicalComponentToMathCoupling const> topo_comp_coup;

The ComponentTopology will be constructed after the model adds all the components. It cannot be changed. When the user copies the model (via C or Python API), the same ComponentTopology will be shared between multiple instances of MainModel. We as PGM developer cannot possibly know the ownership hierarchy (if any) of difference copies of the MainModel. Therefore, using a std::shared_ptr is justified.

Similar applies to MathModelTopology and TopologicalComponentToMathCoupling. When a model has cached math topology, and it get copied. The same topology can be shared between different instances. When one of the copied model refreshes the topology, the ownership of the old topology from that instance is released. But the old topology can still be owned by other copies, until all the copies of the model refresh the topology.

Top-down logical flow

There are many places, however, where the logical flow is strictly top-down. In these places, usage of std::shared_ptr is not justified. An example is shown below:

std::shared_ptr<DoubleVector const> phase_shift_;
std::shared_ptr<SparseGroupedIdxVector const> load_gens_per_bus_;
std::shared_ptr<DenseGroupedIdxVector const> sources_per_bus_;
std::shared_ptr<std::vector<LoadGenType> const> load_gen_type_;

The IterativePFSolver should not own the resource of phase_shift (which is part of MathModelTopology). In the logical flow, if the current the MathModelTopology is destroyed, so will IterativePFSolver also be destroyed. It does not make sense to let IterativePFSolver to own this resource. This just create extra useless abstraction. It also complicates writing the test code. Now we have to create a shared resource in the test code for the class to consume.

Proposal

We propose to remove the std::shared_ptr when shared ownership is not needed, i.e., we can know strictly that the resource will outlive the scope of the object by looking at the logical flow. We can change those members into one of following alternatives:

  • Raw pointer: this is most straightforward to apply.
  • Reference member: this can be interesting, but it makes the class not assignable.
  • For vector like stuff, we can use a std::span.

The choices is still under discussion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    improvementImprovement on internal implementation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions