0

I read that it is perfectly safe to return a struct by value from a function.

Is it safe to return a struct in C or C++?

Would it still be safe if you return multiple structs as a vector ?

e.g.

std::vector<mystruct> func(int c, int d){
    mystruct retval;
    retval.a = c;
    retval.b = d;

    std::vector<mystruct> structList;

    structList.push_back(retval);

    // create more structs and add them to list
    ..
    return structList;
}

And why ? Is it only safe for primitives e.g. numbers since no memory needs to be allocated?

Community
  • 1
  • 1
Steve
  • 738
  • 1
  • 9
  • 30
  • It is safe for any sanely designed type. In other words, if it isn't safe then that's a bug in the user defined type, not in the vector class template. – juanchopanza Feb 17 '15 at 12:19
  • 1
    A vector *is* a struct. There's nothing special about it. – molbdnilo Feb 17 '15 at 12:20
  • @molbdnilo: Nothing special, apart from it's non-default special member functions. Those are what determine whether a type can be safely copied, moved, returned from functions, etc. – Mike Seymour Feb 17 '15 at 12:29

1 Answers1

4

It's safe as long as the mystruct class is properly written, which means it supports copy construction and assignment and/or moving, and proper destruction, with the implied value semantics.

Put another way: "returning a vector" thing isn't the hard part here, it's making sure if you've got one T t1; in any valid state, then you can say T t2(t1); and/or T t3; t3 = t1; and/or let any T go out of scope / be deleted and nothing bad or unexpected will happen. If your T works for those scenarios, all's good to use it in a vector<T>, even for returning by value from a function.

But which structs are safe for that? mystruct is ok to copy/move construct/assign and destroy if it's careful to only make non-static data members one of the following types, and any base classes do similarly:

  • simple data types like int, double, bool etc.

  • self-managing types with value semantics, whether you wrote them yourself or they're provided by the Standard library or another library - e.g. std::string, std::map, std::vector, std::list etc. these know how to copy/move themselves properly

  • arrays of such types

  • std::shared_ptr to data you do actually want shared ownership of, or std::unique_ptr<> to data that can be moved but not copied

  • references, if it makes sense for a copy of the object to refer to the same place

  • other structs and/or classes whose members and base classes satisfy the above conditions

But not raw pointers (unless to some deliberately shared data with a lifetime greater than the objects, e.g. a static const variable or string literal): for new/new[]-ed data the object's meant to manage lifetime for, you need to write your own copy constructor and/or move constructor, copy assignment and/or move assignment operator, and destructor. It's usually much easier and better to use a std::shared_ptr<> or std::unique_ptr<> instead.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • so for a generic struct with int,float etc members i do not need a copy constructor to take care off? – Steve Feb 17 '15 at 12:30
  • @Steve: that's right... the compiler will take care of it all for you. – Tony Delroy Feb 17 '15 at 12:38
  • I'd `s/and optionally/or/` whenever it appears in front of "moving" or "move constructor". You often don't implement both. And in most cases you'll want to write none of them at all and let lower level handlers give you them for free. – rubenvb Feb 17 '15 at 12:39
  • It is not inherently wrong for a struct to contain raw pointers, but it is necessary to consistently manage lifetime of what such pointers point at if instances of the struct are to be stored in a standard container (e.g. making a sensible choice on whether the copy constructor does a deep or shallow copy, based on what is actually being pointed at). Yes, the C++11 standard smart pointers make that easier and are safer, but it is possible - with care - to manage raw pointers (and pointees) appropriately. – Rob Feb 17 '15 at 12:43