RVO on different compilers when using containers - c++

I have the following code on c++17
template<typename T>
std::vector<T*> getPointerVector(std::vector<T> base) {
auto out = std::vector<T*>();
for (auto& t : base) {
out.push_back(&t);
}
return out;
}
As far as i understand RVO should kick in and prevent any copying of the returned vector. However, when i use GCC it all works fine, using msvc it does not and the vector is actually copied. Any explanations? Thanks!
Edit:
When I debugged I made sure the reference in memory is the same for the vector inside the function and on the calling side. That is true for gcc 8.3 on debian testing and not true for msvc on visual studio 19.4

Apparently your version of Visual Studio just doesn't do that.
Or…
When I debugged I made sure the reference in memory is the same for the vector inside the function and on the calling side. That is true for gcc 8.3 on debian testing and not true for msvc on visual studio 19.4
If you're debugging, presumably you're making a debug build, for which optimisations are usually much less fierce. So it could simply be that you turned this off.
It will at least be moving the vector, so there's that.
By the way, every element of the vector you're returning is a dangling pointer. Did you mean to take base by reference? Also, an out.reserve(base.size()) call wouldn't hurt.

Related

Problem passing std::string though DLL boundaries with visual studio

I have a DLL that contains some code like this:
class Info {
int a
int b
int c
std::string str1;
std::string str2;
};
__declspec(dllexport) class C {
Info getInfo();
}
I compile this code with Visual Studio 2015, and calling C::getInfo() works perfectly fine on my system.
Now somebody else is trying to use the DLL, and he's also using Visual Studo 2015. The call goes well but the strings don't contain any accessible data. Even the debugger reports "Error reading characters of string", and the program crashes when trying to read it.
There was also a similar problem with std::vector which I could solve by inlining the code that created the vector.
To me this looks like either the other person is using a different STL version, or the compiler somehow produces a different memory layout for std::string (though he claims to use default settings).
Is this possible? I saw there are different updates for VS 2015 and we might not have the same updates installed.
Any recommendations for fixing this? I can't move to char* without significantly breaking the API. Most users don't even use Visual Studio (or Windows), so this hasn't been a problem until now.
That's life I'm afraid. Unless you have exactly the same compiler (including C++ Standard Library) and compiler settings, this is not guaranteed to work. I'm not convinced from a C++ Standards perspective that even this is guaranteed to work. It's pretty nigh on impossible to build an ABI in C++. In your specific example, there's no guarantee that the struct will be built with the same alignment characteristics. sizeof(std::string) varies considerably due in part to short string optimisations which can even be compiler-configurable.
Alternatives:
Use C linkage for your exported functions and char*-style interfaces that are allocated and deallocated by the caller (cf. the Windows API). (Don't ever allocate memory in the client and deallocate in the dll, and vice-versa.)
Make sure the user of your library can build it from the source files. Consider distributing as a static library rather than a dynamic one, as the former are a little easier to work with.

Function try block in Visual C++ 2008

Does Visual C++ 2008 support function try block inside methods?
I tried this code:
class Foo
{
public:
void f()
try {}
catch ( ... ) {}
};
but the compiler prints this error:
error c2590: 'f' : only a constructor can have a base/member initializer list
The same syntax (valid, according to the standard) works inside a free function.
The code compiles on newer versions of Visual Studio and on gcc.
EDIT: no, in my code there is not a typo. C++ standard says it's a valid syntax. It's called "function try block".
EDIT 2: if I move the method definition outside the class definition, visual c++ 2008 compiles correctly.
Thanks.
This features is only valid for constructors to catch exceptions in inline initializations of member variables, example:
struct a {
a(const complex_object& value)
: m_var(value)
{}
private:
complex_object m_var;
};
If there is an exception throw in copy constructor of complex_object there is no way of handled (no without changing the initialization of m_var).
http://msdn.microsoft.com/en-us/library/e9etx778%28v=vs.90%29.aspx
In this case the function-try block are used to handled such exception maintaining the same initialization.
In your case method f is not a constructor of class Foo.
Daniele is right Function-Try Block could be used in methods, but normally this don't improve much, in this case is better a try-catch block inside method body (permitting returning values from catch block if necessary).
VS2008, was not a version focused in standardization of C++, VS2010 improve this problem but i think not enough, later version VS2012 and specially VS2013 are really getting close to conformant enough (specially in day to day usage), they have some remaining old hard problems, two phases lookups and preprocessor, that in corner case can blow your mind trying to solved, specially treating with portable code (compiled addicionally with GCC, Intel, etc...), but the actual status is really improved.

Make a function returning temporary object inline?

I'm writing an iterator for a new container in c++. When I call begin() and end() functions (both very short), I expected the compiler to make it inline. But it didn't. I think maybe it's because the iterator is returned as a temporary object, and it needs to be copied. I think maybe I can use the RValue reference in c++11, but I'm not familiar with it. So is there a way to make it inline?
The code is something like this (not exactly the same, but I think if this version works, my code will also work)。
I'm using VC++ 2013 CTP, and I have changed compile options but it doesn't work either.
class Pointer
{
public:
Pointer(int* p) : p(p)
{
(*p)++;
}
Pointer(const Pointer& pointer) : p(pointer.p)
{
(*p)++;
}
Pointer& operator =(const Pointer& pointer)
{
(*p)--;
p = pointer.p;
(*p)++;
}
int* p;
~Pointer()
{
(*p)--;
}
static Pointer create(int& p)
{
return Pointer(&p);
}
static Pointer create2(int& p)
{
return create(p);
}
};
int main()
{
int p = 0;
Pointer pointer = Pointer::create2(p);
}
The function create and create2 here are not inline even if, you can see, it's really simple.
I know maybe this doesn't make a difference in the speed of my program, but I just want to have it better.
There are several cases where microsoft's compiler cannot inline functions:
http://msdn.microsoft.com/en-us/library/a98sb923.aspx
In some cases, the compiler will not inline a particular function for mechanical reasons. For example, the compiler will not inline:
A function if it would result in mixing both SEH and C++ EH.
Some functions with copy constructed objects passed by value when -GX/EHs/EHa is on.
Functions returning an unwindable object by value when -GX/EHs/EHa is on.
Functions with inline assembly when compiling without -Og/Ox/O1/O2.
Functions with a variable argument list.
A function with a try (C++ exception handling) statement.
Because the functions return Pointer by value and it has a destructor, the functions cannot be inlined.
There's nothing that can really be done about it other than changing the Pointer class. Rvalue refs don't help here. I would just leave the code as it is and if you need better performance in final product, try another compiler.
RVO may happen here but it doesn't make difference because the cost of copying is so small.
In the C languages there is simply no way to force inlining. inline is just a hint to the compiler to perform inlining, but it is not required to do so.
The only way to "force inline" would be to use preprocessor macros, but that's easy to get wrong. Wrong in that the macro doesn't do what you expect, and wrong in that the macro actually produces slower code. Also, preprocessor macros are no substitute for member functions.
So, if the compiler doesn't want to inline, there's not much you can do about it, and nothing you should do about it.
The answer by Timo is correct for any combination of the /EH?? flag (and /EH?? must be specified to allow any useful exception handling), specifically, MSVC Studio-2015 as well as Studio-2017 15.1 and 15.2 versions will not ever inline a function call if a D'tor is present.
However, I recently found a UserVoice Issue -- Support inlining for functions returning unwindable objects -- for this: (Dec', 2016)
Within deeply-templated codes, it seems quite common to call a
function which simply forwards the arguments into another function,
which again just forwards the arguments into another function, which
again just do forwarding, and so on. As I know, current version of
Visual C++ is not able to inline such a function if it returns an
object with non-trivial destructor, whenever exceptions are enabled.
This often makes a performance hit particularly when the level of
forwarding is unavoidably deep and there are many arguments with
not-so-small sizes. I very much hoped if the upcoming Visual C++ 2017
has solved this problem, but it seems not.
And a comment that states it will be fixed in VS2017 v15 .3 and links to a connect issue where a comment states:
The inlining limitation was because of the presence of exception handling. We have recently improved our inliner and it can now inline std::make_unique in the case you provided. Please download the latest VS 2017 version to try it out. Note that in VS 2017 RTM, this new inlining is off by default, but you can turn it on by adding the flags /d1ReturnUdtEHInline /d2ReturnUdtEHInline to cl.exe. It will be on by default in a future release.
Note that /d1 and /d2 switches are undocumented switches for the front/backend of the compiler.
and
You should expect it to be on by default in the VS 2017 15.3 release.
So, maybe there's hope this will be actually fixed in VS2017 U3.
Two short Godbolt examples to experiment with:
https://godbolt.org/g/1y9UpE
https://godbolt.org/g/3mAzGe

Visual Studio 2012 lambda with unique_ptr argument regression?

I was surprised to find in Visual Studio 2012 Update 1 the following does not compile anymore:
[](unique_ptr<int>){};
Compiler error states it can't access the private copy constructor of unique_ptr.
The above worked just fine in Visual Studio 2010.
It also compiles just fine in gcc 4.7.2
Is this a known bug, or is this actually expected behavior? I could not find anything on Microsoft Connect.
EDIT: I have just updated to Visual Studio 2012 Update 2, the issue still occurs.
EDIT2: I have filed a bug report on Microsoft Connect, you are welcome to upvote it if it affects you too.
Try this:
int a;
[a](unique_ptr<int>){};
It doesn't matter what it is, just capture something explicitly.
I am still not sure whether this is a bug, it certainly looks like it.
In the meantime, a logical equivalent of
[](unique_ptr<int> aArg)
{
};
can be written as
[](unique_ptr<int> && aArg)
{
unique_ptr<int> arg = std::move(aArg);
};
It's not a very nice approach for me as I am writing library code. The lambda's caller is the library and the lambda is user provided. I do not wish to impose on users that they manually std::move the argument.
So, while this is not practical for me, it might come in handy to someone else.

Visual studio to gcc, code compiles well in gcc but gives std::badalloc error at runtime

I have a big code that uses only standard C++ libs and compiles well in gcc. As the code was actually written in VS C++ 6.0. The code runs fine in visual studio but when I use gcc compiler it gives no errors on compilation and when I run it it gives this error
"terminate called after throwing an exception at instance std::bad_alloc what() bad alloc"
One more confusion is that it is a numerical simulation code, it doesn't show any exception while using gdb debugging and terminates successfully but doesn't show the right results. But using gdb it doesn't terminates anywhere. So thats where I am stuck. I am unable to diagnose where does the bad_alloc is actually happening.
The code consists of C and C++ routines
Memory is allocated through new
gdb doesn't show any segabort or any exception during debugging
How can I debug this problem?
If you're on Linux, give valgrind a try for debugging.
VC++ 6.0 is not exactly standards compliant. The upgrade of the compiler (to a newer version) will catch previously unseen errors.
There are three things you can do:
Get are core dump from the unix version (I'm assuming you're using using gcc on a variant of unix), and then use gdb in a post-mortem manner to see where exactly the exception is triggered.
Use a more recent version of Visual C++ (For example free Express 2010 edition) to check the software
Rewrite your allocations to be more robust. i.e.: check for null values. Also you might override the new operator to do this globally.
An exception object, even std::bad_alloc, is still an object and needs to be constructed before it can be thrown. Hence, a breakpoint on std::bad_alloc::bad_alloc will break execution before it's thrown.
Exceptions are meant to identify runtime errors, so the fact that the code compiles and then throws an exception at runtime is perfectly reasonable. std::bad_alloc means that you're running out of memory.
However, tracking down why you're running out of memory is the hard thing. I recently worked on some code that hadn't been updated since Visual C++ 6 and it turns out had a serious bug due to Visual C++ 6's nonstandard treatment of code. The problem was basically:
long foo(int i)
{
return foo(long(i));
}
long foo(long& l)
{
return l * 100;
}
This is syntactically correct code. However, Visual C++ 6 does something wrong here: it interprets the call foo(long(i)) as calling long foo(long& l). This is incorrect. The expression long(i) creates a temporary object and temporary objects cannot bind to non-const references. So, according to C++ standard method overload resolution, this simply calls long foo(int i) again and again recursively. In my case, the infinite recursion caused a stack overflow. To fix this problem, long foo(long& l) needs to be either long foo(long l) or long(const foo& l). I suspect you will find a similar problem in your code, but due to memory allocations you're getting a memory overflow before you get a stack overflow.
I fixed my problem by running Google's cpplint.py and looked for errors regarding non-cosnt references.