Skip to content

Avoid manual memory management ImageSeriesReader::m_MetaDataDictionaryArray#5280

Merged
dzenanz merged 2 commits intoInsightSoftwareConsortium:masterfrom
N-Dekker:Style-m_MetaDataDictionaryArray
Mar 18, 2025
Merged

Avoid manual memory management ImageSeriesReader::m_MetaDataDictionaryArray#5280
dzenanz merged 2 commits intoInsightSoftwareConsortium:masterfrom
N-Dekker:Style-m_MetaDataDictionaryArray

Conversation

@N-Dekker
Copy link
Copy Markdown
Contributor

No longer manually allocated the MetaDataDictionary objects of ImageSeriesReader on the heap. Stored them in an internal std::vector instead.

Declared ImageSeriesReader::m_MetaDataDictionaryArray private, just like ImageSeriesWriter::m_MetaDataDictionaryArray.

Declared `ImageSeriesReader::m_MetaDataDictionaryArray` private, just like
`ImageSeriesWriter::m_MetaDataDictionaryArray`.

Following C++ Core Guidelines, Oct 3, 2024, "Avoid `protected` data",
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-protected

Note that the dictionaries of `ImageSeriesReader` remain publicly accessible by
`GetMetaDataDictionaryArray()`.
@github-actions github-actions Bot added the area:IO Issues affecting the IO module label Mar 17, 2025
Copy link
Copy Markdown
Member

@blowekamp blowekamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am not mistaken this introduces extra copies to the dictionary.

EncapsulateMetaData<double>(newDictionary, "ITK_non_uniform_sampling_deviation", spacingDeviation);
}
m_MetaDataDictionaryArray.push_back(newDictionary);
m_InternalMetaDataDictionaries.push_back(newDictionary);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying the dictionary is a non-trivial task. The prior implementation used pointer to ensure extra copying was not done. This now needs to manually be done.

This should be "emplace_back" to reduce copying the dictionary. Also when the vector is resize, it will copy the dictionaries. The vector should reserve the expected number of dict ( aka number of slices.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blowekamp Thanks for expressing your concern, but I think you are mistaken. Copying a dictionary is actually pretty fast, now that it has "copy on write". For more than six years already:

No problem, I can add a vector::reserve call, and a std::move, but I don't expect a major performance change 🤷

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blowekamp Please check if your concern is taken away by this force-push

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh... Thanks for the link, lol. And thank you for using the move semantics which is fine, I agree it will not make much difference given the "brilliant" implement in the DataDictionary 🤣

Side details discussion: I do find your C++ changes interesting and frequently learn things from them. Thank you. I suppose resizing and vector where the objects support move semantics is not too expensive, even without lazy copying.

No longer manually allocated MetaDataDictionary objects on the heap. Stored them
in an internal `std::vector` instead.
@N-Dekker N-Dekker force-pushed the Style-m_MetaDataDictionaryArray branch from b128652 to d7150cd Compare March 17, 2025 21:11
@N-Dekker N-Dekker marked this pull request as ready for review March 17, 2025 21:48
@blowekamp blowekamp self-requested a review March 18, 2025 13:16
@dzenanz dzenanz merged commit 7d2bb40 into InsightSoftwareConsortium:master Mar 18, 2025
Comment on lines -467 to +445
m_MetaDataDictionaryArray.push_back(newDictionary);
m_InternalMetaDataDictionaries.push_back(std::move(newDictionary));
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@blowekamp Regarding your suggestion to use "emplace_back": in this particular case I think emplace_back and push_back are basically equivalent, technically. emplace_back(newDictionary) would have copied newDictionary, albeit "in-place" ("emplaced"). emplace_back(std::move(newDictionary)) would have moved newDictionary. But the current push_back(std::move(newDictionary)) also just moves newDictionary.

In general, emplace_back is more interesting as an alternative to push_back(MyClass(a, b, c)), to replace it with emplace_back(a, b, c). (See also clang-tidy use-emplace.)

I don't think the guideline is to always replace push_back with emplace_back. 🤷

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the usage of emplace_back would have been to remove the local variable... something like:

m_InternalMetaDataDictionaries.emplace_back(reader->GetImageIO()->GetMetaDataDictionary());

My thought had been to use emplace_back to avoid extra copies of the objects being created. For this particular object it doesn't master. And your implementation is nearly equivalent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the usage of emplace_back would have been to remove the local variable... something like:

m_InternalMetaDataDictionaries.emplace_back(reader->GetImageIO()->GetMetaDataDictionary());

OK, but then it still wouldn't be much different from using push_back, as follows:

m_InternalMetaDataDictionaries.push_back(reader->GetImageIO()->GetMetaDataDictionary());

In either way (whether "emplacing" or "pushing"), it would always have to make a copy of the dictionary from the ImageIO object. 🤷 Fortunately copying a dictionary is very fast now, because of Copy On Write (your PR #455).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:IO Issues affecting the IO module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants