|
|||
|
I was wondering how the following function could be made exception-
neutral: std::vector<std::string> list1, list2; void f(std::string const &x) { list1.push_back(x); list2.push_back(x); } What if you couldn't redesign the problem and list1 and list2 needed to be separate? Is there any way for f() to be guaranteed exception-neutral (by the standard), and efficient (i.e. O(1))?? The only approaches I can think of involve a pop_back() (which is not guaranteed by the standard), or a copy, which is not efficient. void f2(std::string const &x) { list1.push_back(x); try { list2.push_back(x); } catch(...) { list1.pop_back(); // Might throw? throw; } } void f3(std::string const &x) { std::vector<std::string> tmp1(list1); // Inefficient std::vector<std::string> tmp2(list2); // Inefficient tmp1.push_back(x); tmp2.push_back(x); list1.swap(tmp1); list2.swap(tmp2); } void f4(std::string const &x) { std::vector<std::string> tmp(list1); // Inefficient tmp.push_back(x); list2.push_back(x); // Assume exception-neutral? list1.swap(tmp); } Which is best? Is it safe to even assume that std::vector: ush_back() isexception-neutral? Any sane implementation would be, but I don't see it documented anywhere. But it might even be plausible for std::vector: op_back() to throw, if for example it decided toautomatically reduce its allocated size to save space, but in doing so manages to throw in a copy constructor? Calum [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|
||||
|
||||
|
|
|
|||
|
Calum Grant wrote:
> I was wondering how the following function could be made exception- > neutral: > std::vector<std::string> list1, list2; > > void f(std::string const &x) > { > list1.push_back(x); > list2.push_back(x); > } > The only approaches I can think of involve a pop_back() (which is not guaranteed by the standard) Why do you think pop_back is not guaranteed by the standard? Also, the standard requires that pop_back does not throw. > void f2(std::string const &x) > { > list1.push_back(x); > try > { > list2.push_back(x); > } > catch(...) > { > list1.pop_back(); // Might throw? > throw; > } > } Yes, this is correct, except from the comment. > Is it safe to even assume that std::vector: ush_back() is> exception-neutral? Any sane implementation would be, but I don't see it > documented anywhere. Independently of push_back implementation, your copy constructor, operator = , or allocator may throw, and exception would be propagated to your code. > But it might even be plausible for std::vector: op_back() to throwNo, this is not allowed by the standard. -- Valentin Samko - http://www.valentinsamko.com [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Calum Grant <calumg@onetelc.om> writes:
> I was wondering how the following function could be made exception- > neutral: > > std::vector<std::string> list1, list2; > > void f(std::string const &x) > { > list1.push_back(x); > list2.push_back(x); > } It's already exception-neutral. > What if you couldn't redesign the problem and list1 and list2 needed > to be separate? I think you're looking for the answer to, "how can it be made to give the strong guarantee?" > Is there any way for f() to be guaranteed exception-neutral (by the > standard), and efficient (i.e. O(1))?? The only approaches I can think > of involve a pop_back() (which is not guaranteed by the standard) Not guaranteed how? > or a copy, which is not efficient. > > void f2(std::string const &x) > { > list1.push_back(x); > try > { > list2.push_back(x); > } > catch(...) > { > list1.pop_back(); // Might throw? No, it's guaranteed not to throw. 23.1 Container requirements 23 Containers library 10 Unless otherwise specified (see 23.2.1.3 and 23.2.4.3) all container types defined in this clause meet the following additional requirements: * if an exception is thrown by an insert() function while inserting a single element, that function has no effects. * if an exception is thrown by a push_back() or push_front() function, that function has no effects. * no erase(), pop_back() or pop_front() function throws an exception. > throw; > } > } > > Is it safe to even assume that std::vector: ush_back() is> exception-neutral? Almost, but not quite. However, it's safe to assume it gives the strong guarantee. See the 2nd bullet above. > Any sane implementation would be, but I don't see it documented > anywhere. But it might even be plausible for > std::vector: op_back() to throw, if for example it decided to> automatically reduce its allocated size to save space, but in doing > so manages to throw in a copy constructor? Nope. -- Dave Abrahams Boost Consulting www.boost-consulting.com [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
David Abrahams wrote:
> Calum Grant <calumg@onetelc.om> writes: > > >>I was wondering how the following function could be made exception- >>neutral: >> >> std::vector<std::string> list1, list2; >> >> void f(std::string const &x) >> { >> list1.push_back(x); >> list2.push_back(x); >> } > > > It's already exception-neutral. > > >>What if you couldn't redesign the problem and list1 and list2 needed >>to be separate? > > > I think you're looking for the answer to, "how can it be made to give > the strong guarantee?" Yes, you are absolutely right. What do you think of the solution provided by the Atomic library (http://visula.org/atomic)? atomic::vector<std::string> list1, list2; void f(const std::string &s) { atomic::transaction tr; list1.push_back(s); list2.push_back(s); tr.commit(); } This is an open-source library I am working on, which uses transactions as a means of providing a strong exception guarantee. Your expert feedback would be most welcome. Calum [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Calum Grant <calumg@onetelc.om> wrote:
> I was wondering how the following function could be made exception- > neutral: > > std::vector<std::string> list1, list2; > > void f(std::string const &x) > { > list1.push_back(x); > list2.push_back(x); > } > > What if you couldn't redesign the problem and list1 and list2 needed to > be separate? > > Is there any way for f() to be guaranteed exception-neutral (by the > standard), and efficient (i.e. O(1))?? The only approaches I can think > of involve a pop_back() (which is not guaranteed by the standard), or a > copy, which is not efficient. Have a look at 23.1/10. This guarantees that pop_back() won't throw and push_back() is strongly exception-safe (i.e. if it throws it doesn't change the container). This pararaph refers to exceptions (no pun intended) for vector in 23.2.4.3, but those are for the insert and erase members which in general may need to call copy-assignment operators for following elements. pop_back and push_back obviously never do that. <snip> > Which is best? Clearly f2, as it is both safe and efficient. > Is it safe to even assume that std::vector: ush_back() is> exception-neutral? Yes. > Any sane implementation would be, but I don't see it > documented anywhere. But it might even be plausible for > std::vector: op_back() to throw, if for example it decided to> automatically reduce its allocated size to save space, but in doing so > manages to throw in a copy constructor? I don't think vector implementations are allowed to reduce their capacity. Ben. -- Ben Hutchings Having problems with C++ templates? Your questions may be answered by <http://womble.decadentplace.org.uk/c++/template-faq.html>. [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|||
|
Calum Grant <calumg@onetelc.om> writes:
> What do you think of the solution provided by the Atomic library > (http://visula.org/atomic)? > > atomic::vector<std::string> list1, list2; > > void f(const std::string &s) > { > atomic::transaction tr; > list1.push_back(s); > list2.push_back(s); > tr.commit(); > } > > This is an open-source library I am working on, which uses transactions > as a means of providing a strong exception guarantee. Your expert > feedback would be most welcome. I guess if you can afford the 10% performance hit and you can control all the types in use to be sure they're atomic::-enabled, it's probably very convenient. If not, you have to step back and use something more general and efficient like scopeguard. -- Dave Abrahams Boost Consulting www.boost-consulting.com [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ] |
|
|
![]() |
| Thread Tools | |
| Display Modes | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Re: Throwing an exception leads to termination! | Arne Mertz | Newsgroup comp.language.c++.moderated | 6 | 04-04-2009 04:07 AM |
| Re: Throwing an exception leads to termination! | Bart van Ingen Schenau | Newsgroup comp.language.c++.moderated | 0 | 04-01-2009 03:30 AM |
| Make easy money!! NO SCAM!! Please Read! | sulliman24@gmail.com | Newsgroup comp.soft-sys.sas | 0 | 03-01-2005 10:15 PM |
| Ah An Easier Way To Make Money | giveitatry369@msn.com | Newsgroup comp.soft-sys.sas | 0 | 02-23-2005 10:27 PM |
| Re: MAKE MONEY USING PAYPAL | frisbee_wizard@yahoo.com | Newsgroup comp.soft-sys.sas | 0 | 01-11-2005 05:05 PM |