-1

Example: A wrapper for std::vector. I have 2 move constructors:

template <class Allocator>
class MyVector {
  ....
  MyVector(MyVector&&) = default;
  MyVector(MyVector&& other, const Allocator<int>& alloc) : vec(std::move(other.vec), alloc) {}
private:
      std::vector<int, Allocator<int>> vec;

  ...
}

However, I want to do an optimization to avoid a costly constructor of vector in case that the given memory allocator is the same as in the moved parameter. Something like:

class MyVector {
  MyVector(MyVector&& other, const Allocator<int>& alloc)
      : if (other.vec.get_allocator() == alloc) 
            vec(std::move(other.vec)) 
        else 
            vec(std::move(other.vec), alloc) 
        {}
}

Is this even possible in C++?

Note: Question Right way to conditionally initialize a C++ member variable? is not similar, as I cannot push the condition inside the base constructor function call. I need it outside to choose the base constructor.


Context: A third party library code, which I can't change, uses the wrong move constructor (passing allocator when it should not be passed), which I am trying to fix, because it extremely harms the performance.

More context: The problematic code is std::scoped_allocator_adaptor. It treats std::pair as a container, which makes that problem.

Having set<pair<int,MyVector>>, and using 1 scoped allocator for all memory allocations, it generates the wrong constructor in allocator_traits::construct(). The moved MyVector indeed uses the same allocator, but it is obscured by the pair, and the fact that vec.get_allocator() == set.get_allocator() is ignored. So pair construction invokes the move constructor of MyVector with the unnecessary alloc parameter.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
DanielHsH
  • 4,287
  • 3
  • 30
  • 36
  • 2
    No you can't do this in c++, explaining your actual problem in more detail with a [mre] might make a better question – Alan Birtles Sep 04 '22 at 08:16
  • 1
    No, the member-initializer-list can not have if-else statements. Try to post a _valid_ reproducible C++ code: `const Allocator& alloc` the .. `Allocator` is not a template that can take a template argument. – mada Sep 04 '22 at 08:55
  • 1
    As others have said, we need more details, including code that is (nearly) compilable. But you can maybe use a conditional (`?:`) operator in the initializer list. – Adrian Mole Sep 04 '22 at 10:44
  • Vector's allocator-extended move constructor (overload (9) [here](https://en.cppreference.com/w/cpp/container/vector/vector)) already optimizes for `alloc == other.get_allocator()` – Igor Tandetnik Sep 04 '22 at 15:44
  • As an initial matter, `Allocator` is a name of a type and not a template, in light of which `Allocator` doesn't make sense. – Igor Tandetnik Sep 04 '22 at 15:49
  • Something [along these lines](https://godbolt.org/z/McE9M5cxa), perhaps. – Igor Tandetnik Sep 04 '22 at 15:52
  • The exact code is not important for the question, as the question was about C++ syntaxt, I gave the context as an FYI, was not actually asking about allocators. And the move construct does check that alloc == other.get_allocator() but it happens too deep inside the code so a considerable measurable penalty is incurred. – DanielHsH Sep 05 '22 at 08:01

1 Answers1

0

Thanks for the comments on the question. Summarizing them as an asnwer.

  1. It seems impossible to use condition to select base constructors.
  2. As a solution I removed the scoped allocator adaptor and just changed the code from MyVector v; v.emplace_back() to v.emplace_back(MyVector::value_type{v.get_allocator()}; thus effectively adding the scoped behaviour by myself. That bypassed the problematic slow constructor and I indeed measure a considerable gain in speed. Same changes were done for other containers, like sets
  3. Will not add a sample code as it is specific to my problem and not related to the original question, which was purely about C++ syntax.
DanielHsH
  • 4,287
  • 3
  • 30
  • 36