std::string generates linker error -- const char* does not. why? - c++

just like the headline says.. i got this piece of code
std::string dir;
(ls == 1) ? dir = "Long" : dir = "Short";
which generates error i don´t understand
LNK2019: unresolved external symbol _CrtDbgReportW referenced in function
"void * __cdecl std::_Allocate(unsigned __int64,unsigned __int64,bool)
when i switch to
const char* dir;
(ls == 1) ? dir = "Long" : dir = "Short";
all works pretty fine.
what is the deal there?

In
std::string dir;
(ls == 1) ? dir = "Long" : dir = "Short";
dir is a std::string, a fairly complex class that will be pulling in bits and pieces from all over the standard library, including memory allocation which appears to be calling a Windows debug helper function, _CrtDbgReportW, under some circumstances. For whatever reason, this debug helper function is not being linked.
But in
const char* dir;
(ls == 1) ? dir = "Long" : dir = "Short";
dir is just a simple pointer, an address. dir = "Long" simply points dir at the string literal "long". This is just a simple assignment that requires no help from any libraries.

Related

Sprite::create(“file.png”) return null on Cocos2d-x C++ Visual Studio

I'm trying to create a Sprite with SonarFrameworks, and get a null although my file is well integrated into the project.
I tried to add :
FileUtils::getInstance()->addSearchPath("res/");
And try with Content property set to "True" and "False" (default), but still same problem.
Any idea ?
Thanks to GandhiGandhi I found the solution :
In the function FileUtils::fullPathForFilename located in the file CCFileUtils.cpp, a added this
std::string search = searchIt;
int tail = search.size() - 10; // For replace /Resources
search.replace(tail, 9, "res");
After the first "for(...){", so like that I replaced the path to find my resources.
for (const std::string& searchIt : _searchPathArray)
{
std::string search = searchIt;
int tail = search.size() - 10; // For replace /Resources
search.replace(tail, 9, "res");
for (const auto& resolutionIt : _searchResolutionsOrderArray)
{
fullpath = this->getPathForFilename(newFilename, resolutionIt, search);
if (!fullpath.empty())
{
// Using the filename passed in as key.
_fullPathCache.emplace(filename, fullpath);
return fullpath;
}
}
}

`std::filesystem::path::operator/(/*args*/)` not working as expected

I have a class with an initialiser list in the constructor where one of the fields I'm initialising is a std::filesystem::path but it doesn't seem to be initialising to the expected value.
MyClass::MyClass(
unsigned int deviceSerial,
const std::string& processName
) :
deviceSerial(deviceSerial),
processName(processName),
configFilePath(GetBasePath() / std::to_string(deviceSerial) / ("#" + processName + ".json"))
{
/* Parameter checks */
}
Using the debugger I can see that GetBasePath() is returning exactly what I expect (returns std::filesystem::path with correct path) but the / operator doesn't seem to be having an effect. Once inside the body of the constructor I can see that configFilePath is setup to the result of GetBasePath() without the extra info appended.
I'm using MSVS-2019, I have the C++ language standard set to C++17 and in debug mode I have all optimisations disabled.
I have also tested the following in the body of the class and I still see path as simply the result of GetBasePath() and the extra items are not being appended.
{
auto path = GetBasePath(); // path = "C:/Users/Me/Desktop/Devices"
path /= std::to_string(deviceSerial); // path = "C:/Users/Me/Desktop/Devices"
path /= ("#" + processName + ".json"); // path = "C:/Users/Me/Desktop/Devices"
}
On a slight side note I also tried the above test with += instead of /= and I still see the same results.
Edit
As requested, below is a minimal complete and verifiable example.
#include <Windows.h>
#include <cstdio>
#include <filesystem>
#include <memory>
#include <string>
std::string ExpandPath(const std::string &str) {
auto reqBufferLen = ExpandEnvironmentStrings(str.c_str(), nullptr, 0);
if (reqBufferLen == 0) {
throw std::system_error((int)GetLastError(), std::system_category(),
"ExpandEnvironmentStrings() failed.");
}
auto buffer = std::make_unique<char[]>(reqBufferLen);
auto setBufferLen =
ExpandEnvironmentStrings(str.c_str(), buffer.get(), reqBufferLen);
if (setBufferLen != reqBufferLen - 1) {
throw std::system_error((int)GetLastError(), std::system_category(),
"ExpandEnvironmentStrings() failed.");
}
return std::string{buffer.get(), setBufferLen};
}
int main() {
unsigned int serial = 12345;
std::string procName = "Bake";
std::filesystem::path p(ExpandPath("%USERPROFILE%\\Desktop\\Devices"));
std::printf("Path = %s\n", p.string().c_str());
// p = C:\Users\Me\Desktop\Devices
p /= std::to_string(serial);
std::printf("Path = %s\n", p.string().c_str());
// p = C:\Users\Me\Desktop\Devices
p /= "#" + procName + ".json";
std::printf("Path = %s\n", p.string().c_str());
// p = C:\Users\Me\Desktop\Devices
std::getchar();
}
I've also used this example and tested with `p.append()` and got the same result.
I'd like to give thanks to #rustyx and #Frank for their suggestions, following this advice has led me to discover a bug in the way I create the initial string that gets passed to the path constructor (Also #M.M who found the exact bug while I was typing this answer)
I created a function (that is in use in my class) std::string ExpandPath(const std::string& path) which uses the Windows API to expand any environment variables in a path and return a string. This string is generated from a char* and a count, that count includes the null byte so when creating an string using the constructor variant std::string(char* cstr, size_t len) this includes the null byte in the string itself.
Because I was using the debugger to interrogate the variables it reads C-style strings and stops at the null byte. In my original example I also use printf() as I just happen to prefer this function for output, but again this stops printing at the null byte. If I change the output to use std::cout I can see that the output has the expected path but with an extra space their (the null byte being printed as a space). Using std::cout I see that my paths result as the following with each append:
Path = C:\Users\Me\Desktop\Devices
Path = C:\Users\Me\Desktop\Devices \12345
Path = C:\Users\Me\Desktop\Devices \12345\#Bake.json
Summary:
Bug in my ExpandPath() where
return std::string{buffer.get(), setBufferLen};
Should be
return std::string{buffer.get(), setBufferLen - 1};

visual studio 2017 LNK2019: unresolved external symbol In GoogleTestGoogleMock Project

I am a noobie with C++. My first learning project uses GoogleTest and GoolgleMock, but, of course, I am new to those also. I installed googletestmock.v.141 v101 via NuGet. My main app, AstronomyCalculations, builds and runs without a problem. My test app, GMock, throws three LNK2019 errors when I try to build it.
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __cdecl easter::easter(void)" (??0easter##QEAA#XZ) referenced in function "private: virtual void __cdecl GET_THE_DATE_OF_EASTER_ShouldReturnDateOfEaster_Test::TestBody(void)" (?TestBody#GET_THE_DATE_OF_EASTER_ShouldReturnDateOfEaster_Test##EEAAXXZ) GMock D:\Dev\Projects\AstronomyCalculations\GMock\GMock.obj 1
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __cdecl easter::~easter(void)" (??1easter##QEAA#XZ) referenced in function "private: virtual void __cdecl GET_THE_DATE_OF_EASTER_ShouldReturnDateOfEaster_Test::TestBody(void)" (?TestBody#GET_THE_DATE_OF_EASTER_ShouldReturnDateOfEaster_Test##EEAAXXZ) GMock D:\Dev\Projects\AstronomyCalculations\GMock\GMock.obj 1
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: struct tm __cdecl easter::get_easter_date(int)const " (?get_easter_date#easter##QEBA?AUtm##H#Z) referenced in function "private: virtual void __cdecl GET_THE_DATE_OF_EASTER_ShouldReturnDateOfEaster_Test::TestBody(void)" (?TestBody#GET_THE_DATE_OF_EASTER_ShouldReturnDateOfEaster_Test##EEAAXXZ) GMock D:\Dev\Projects\AstronomyCalculations\GMock\GMock.obj 1
// AstronomyCalculations.cpp
int main() {
return 0;
}
// Easter.h
#pragma once
#include <ctime>
#include <string>
class easter
{
public:
easter();
~easter();
tm get_easter_date(int easter_year) const;
};
// Easter.cpp
#include "Easter.h"
easter::easter()
{
}
easter::~easter()
= default;
tm easter::get_easter_date(const int easter_year) const
{
const auto a = easter_year % 19;
const auto b = easter_year / 100;
const auto c = easter_year % 100;
const auto d = b / 4;
const auto e = b % 4;
const auto f = (b + 8) / 25;
const auto g = (b - f + 1) / 3;
const auto h = ((19 * a) + b - d - g + 15) % 30;
const auto i = c / 4;
const auto k = c % 4;
const auto l = (32 + (2 * e) + (2 * i) - h - k) % 7;
const auto m = (a + (11 * h) + (22 * l)) / 451;
const auto easter_month = (h + l - (7 * m) + 114) / 31;
const auto easter_day = ((h + l - (7 * m) + 114) % 31) + 1;
auto date_string = std::to_string(easter_year) +
"-" +
std::to_string(easter_month) +
"-" +
std::to_string(easter_day) +
" 00:00:00";
char date[20]; //a 1 char space for null is also required
strcpy_s(date, date_string.c_str());
tm ltm{};
char seps[] = " -:";
char *next_token = nullptr;
auto token = strtok_s(date, seps, &next_token);
ltm.tm_year = strtol(token, nullptr, 10);
token = strtok_s(nullptr, seps, &next_token);
ltm.tm_mon = strtol(token, nullptr, 10);
token = strtok_s(nullptr, seps, &next_token);
ltm.tm_mday = strtol(token, nullptr, 10);
token = strtok_s(nullptr, seps, &next_token);
ltm.tm_hour = strtol(token, nullptr, 10);
token = strtok_s(nullptr, seps, &next_token);
ltm.tm_min = strtol(token, nullptr, 10);
token = strtok_s(nullptr, seps, &next_token);
ltm.tm_sec = strtol(token, nullptr, 10);
ltm.tm_wday = 0;
return ltm;
}
// GMock.cpp
#include "stdafx.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "Easter.h"
int main(int argc, char** argv)
{
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
TEST(GET_THE_DATE_OF_EASTER, ShouldReturnDateOfEaster)
{
easter estr;
const auto result = estr.get_easter_date(2000);
ASSERT_EQ(result.tm_year, 2000);
}
The linker seems unable to find the functions easter::easter(void), easter::~easter(void), and easter::get_easter_date(int)const
You are obviously including easter.h (and have it in your search path, or the compiler would have complained) but are you actually compiling easter.cpp or a mock object of it? (As far as I can tell from your sourcecode you are not actually mocking the class either). The header file is enough to satisfy the compiler, but when the linker tries to put the application together and realizes it is missing the object file, it balks - throwing LNK2019.
I can only strongly reccommend you look deeper into the documentation available for gtest & gmock.
In addition, you may also reconsider your naming schemes - Class types usually begin with an uppercase (i.e. Easter, not easter) to better tell them from variable names (which begin with lowercase). Also don't call your variables a, b, c, d - const auto a and its ilk are horrible to read, debug, and you will curse yourself I you ever find yourself in the postion of having to revisit the code after some weeks. Even if this were only some practice project, please also practice using good coding standards & naming conventions, so you (automatically) use them on bigger projects.
I finally solved this when I discovered that GoogleTest can be added in Visual Studio 2017 as a new project. Of course, I had to remove my original test project first and then add the new test project. It all worked out in the end, but, of course, I have no idea of why the link errors showed up in my original testing project; other than CharonX's insights.

using openNN in visual studio (unresolved external symbol)

I am looking to use the C++ neural network library "OpenNN".
http://www.opennn.net/
I am relatively new to C++ project management and I believe my issue is caused by this.
I have cloned the openNN repo.
I copied the relevant folders form the repo across in to the folder that i created to contain all OpenNN project i plan to make.
I then made a c++ console application in visual studio, in this folder that i am using for testing.
so dir structure is :
OpenNN (where i plan to keep all openNN projects)
---eigen
---opennn
---tinyxml2
---OpenNNTest (my test project folder)
I have done some testing with the Vector and Matrix classes that are part of OpenNN and that all worked fine.
The below code however returns the following two external symbol errors:
Error LNK2019 unresolved external symbol "public: __thiscall OpenNN::NeuralNetwork::NeuralNetwork(class OpenNN::Vector<unsigned int> const &)" (??0NeuralNetwork#OpenNN##QAE#ABV?$Vector#I#1##Z) referenced in function "void __cdecl NNTest(void)" (?NNTest##YAXXZ) OpenNNTest D:\Projects\OpenNN\OpenNNTest\OpenNNTest\OpenNNTest.obj 1
Error LNK2019 unresolved external symbol "public: virtual __thiscall
OpenNN::NeuralNetwork::~NeuralNetwork(void)" (??1NeuralNetwork#OpenNN##UAE#XZ) referenced in function "void __cdecl NNTest(void)" (?NNTest##YAXXZ) OpenNNTest D:\Projects\OpenNN\OpenNNTest\OpenNNTest\OpenNNTest.obj 1
interestingly, if I change:
OpenNN::NeuralNetwork nn(architecture);
to
OpenNN::NeuralNetwork nn();
No issues, as if it finds the default constructor but not the overloaded one?
The code I am using is as follows:
#include "stdafx.h"
#include "../../opennn/opennn.h"
using namespace OpenNN;
using std::cout;
using std::endl;
void NNTest()
{
OpenNN::Vector<unsigned> architecture(5);
architecture[0] = 2;
architecture[1] = 2;
architecture[2] = 4;
architecture[3] = 3;
architecture[4] = 1;
OpenNN::NeuralNetwork nn(architecture);
//Vector<double> inputs(2);
//inputs[0] = 0.5;
//inputs[1] = 0.1;
//Vector<double> outputs = nn.calculate_outputs(inputs);
//cout << outputs << endl;
//nn.save("neural_network.xml");
}
int main()
{
NNTest();
getchar();
return 0;
}
You need to change the type unsigned to size_t:
OpenNN::Vector<size_t> architecture(5);
architecture[0] = 2;
architecture[1] = 2;
architecture[2] = 4;
architecture[3] = 3;
architecture[4] = 1;
OpenNN::NeuralNetwork nn(architecture);
I hope that helps.

stat & S_IFREG in C++

void fun1(char *fl){
//flNamep : stores the path of our directory
DIR *dip;
struct dirent *dit;
dip = opendir(fl);
if (dip==NULL) {cerr<<"Error\n";exit(-1);}
while ((dit=readdir(dip)))
{
string trun = (dit->d_name);
struct stat buff;
stat(dit->d_name, &buff);
if (((buff.st_mode & S_IFREG)==S_IFREG))
{cout<<"File"<<endl;}
else if (((buff.st_mode & S_IFDIR)==S_IFDIR))
{cout<<"Dir"<<endl;}
}
closedir(dip);
}
Code does not differentiate in dir and files. Am i missing something? I can not use Boost or any other STL. only C Posix Supported files. Need to know were i am wrong.
Updated code as per answer
DIR *dip;
struct dirent *dit;
dip = opendir(flNamep);
if (dip==NULL) {cerr<<"Err\n";exit(-1);}
while ((dit=readdir(dip)))
{
string trun = (dit->d_name);
string fullpath = flNamep;
fullpath+='/';
fullpath+=trun;
if((trun==".") || (trun=="..")) {cout<<"";}
else
{
struct stat buff;
stat(dit->d_name, &buff);
if (((buff.st_mode & S_IFDIR)==S_IFDIR))
{cout<<"Dir"<<endl;}
else
{cout<<"File"<<endl;}
}
I suspect that the stat actually fails with ENOENT (no such file) so buff doesn't contain anything useful.
stat(dit->d_name, &buff); /* dirent.d_name is just the name, not the full path */
You probably want to concatenate fl, "/", d_name. But first of all, check the value returned by stat.