2

I am working on a personal project to familiarize myself with C++11 and Boost.

I have a inheritance relationship with a UrlExtractor base class, with a TagUrlExtractor derived class and a CompoundExtractor derived class. A CompoundExtractor can contain any number of UrlExtractors, thus implementing the composite pattern.

I am curious what the method signature for CompositeExtractor.addExtractor should look like. Since I'm dealing with a polymorphic type, I am forced to work with pointers (or references). I want to use the new smart pointers, specifically shared_ptr.

I tried writing the addExtractor member function like this:

void addExtractor(shared_ptr<UrlExtractor> extractor);

However, I get a compile error if I try to write:

compound.addExtractor(new TagUrlExtractor());

The issue is that it would take two implicit conversions to create a shared_ptr<UrlExtractor>: one to the UrlExtractor base class and second to the shared_ptr.

I could call the function like this:

compound.addExtractor(shared_ptr<UrlExtractor>(new TagUrlExtractor));

However, this is very verbose. How is this situation handled normally?

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
Travis Parks
  • 8,435
  • 12
  • 52
  • 85

1 Answers1

9

The issue is that it would take two implicit conversions to create a shared_ptr: one to the UrlExtractor base class and second to the shared_ptr

That's not the issue: the issue is that the constructor of shared_ptr that accepts a raw pointer is marked as explicit, so it can't be used in a copy-initialization context (function parameters are copy-initialized, as specified by § 8.5/15).

You could (and actually, should) use std::make_shared:

compound.addExtractor(std::make_shared<TagUrlExtractor>());

std::make_shared() has the advantage of being exception-safe and performing one dynamic allocation less than when you are initializing a shared pointer from a new expression (also see this Q&A on StackOverflow).

Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • 1
    That actually eliminates the need to do an explicit `new`. Very nice! – Travis Parks Jun 04 '13 at 18:18
  • 2
    @TravisParks: Indeed, in C++11 you almost never need to use `new` unless you're doing really low-level memory management (like writing your own container and whatnot), and in C++14 you can remove the "almost" - thanks to `std::make_unique()` ;-) – Andy Prowl Jun 04 '13 at 18:19
  • 1
    @AndyProwl: I would argue that `new` is still pretty commonplace until we get `make_unique` (with `unique_ptr` often being the preferable choice). `delete` on the other hand should be pretty much non existant in C++11 code (good ridence). – Grizzly Jun 04 '13 at 18:25
  • @Grizzly: Well, that's pretty much what I wrote in the previous comment ;) – Andy Prowl Jun 04 '13 at 18:26
  • 1
    @AndyProwl: I may not have formulated that all to well. I wanted to express my opinion that "almost" is much to strong to te current situation. – Grizzly Jun 04 '13 at 18:30
  • @Grizzly: I understand what you mean, but my "almost" is there precisely to cover the creation of `unique_ptr` (as the second part of the sentence implies) – Andy Prowl Jun 04 '13 at 18:31