///////////////////////////////////////////////////////////////////////////// // TestClass.cpp - Implemented to Support testing operations on classes // // // // Application: CSE687 - OOD demonstration, Spring 2014 // // Platform: Dell XPS 2720 Touch, Win 8.1 Pro, Visual Studio 2012 // // Author: Jim Fawcett, Syracuse University, CST 4-187 // // jfawcett@twcny.rr.com, http://ecs.syr.edu/faculty/fawcett // ///////////////////////////////////////////////////////////////////////////// #include "TestClass.h" #include "..\Helpers\Helpers.h" #include #include #include #include #include #include // add this to stringUtiltities //----< remove a substring if it exists, returning by value >---------------- std::string remove(std::string& src, const std::string& removed) { std::string modified = src; size_t pos = modified.find(removed); if (pos >= modified.size()) return modified; std::string ret = modified.erase(pos, removed.size()); return ret; } //----< remove a substring if it exists, returning by reference >------------ void inPlaceRemove(std::string& src, const std::string& removed) { size_t pos = src.find(removed); if (pos >= src.size()) return; src = src.erase(pos, removed.size()); } //----< configure output lines into fixed size fields >---------------------- void showLine(const std::string& msg, size_t line, const std::string& function) { std::ostringstream lineStr, funcStr; lineStr << line; funcStr << function; std::string fStr = funcStr.str(); inPlaceRemove(fStr, "__thiscall "); inPlaceRemove(fStr, "__cdecl "); std::cout << "\n " << std::setw(40) << std::left << msg.substr(0, 40); std::cout << std::setw(9) << " at line " << std::setw(5) << std::right << "#" + lineStr.str() + " "; std::cout << std::left << fStr.substr(0, 60); } //----< default constructor >---------------------------------------------- Test::Test() { showLine("void construction of Test",__LINE__, __FUNCSIG__); name_ = "unnamed"; } //----< promotion constructor >-------------------------------------------- Test::Test(const std::string& name) : name_(name) { std::string msg = "named construction of " + name; showLine(msg, __LINE__, __FUNCSIG__); } //----< copy constructor >------------------------------------------------- Test::Test(const Test& t) : name_(t.name_) { std::string msg = "copy of " + name_; showLine(msg, __LINE__, __FUNCSIG__); } //----< move constructor >------------------------------------------------- Test::Test(Test&& t) : name_(std::move(t.name_)) { std::string msg = "move of " + name_; showLine(msg, __LINE__, __FUNCSIG__); } //----< copy assignment operator >----------------------------------------- Test& Test::operator=(const Test& t) { if (this == &t) return *this; name_ = t.name_; std::string msg = "copy assignment of " + name_; showLine(msg, __LINE__, __FUNCSIG__); return *this; } //----< move assignment operator >----------------------------------------- Test& Test::operator=(Test&& t) { if (this == &t) return *this; name_ = std::move(t.name_); std::string msg = "move assignment of " + name_; showLine(msg, __LINE__, __FUNCSIG__); return *this; } //----< destructor >------------------------------------------------------- Test::~Test() { std::string msg = "destruction of " + name_; showLine(msg, __LINE__, __FUNCSIG__); } //----< name "property" >-------------------------------------------------- std::string& Test::name() { return name_; } //----< enunciator >------------------------------------------------------- void Test::say() { std::cout << "\n my name is " << name_; } //----< cosmetic object that emits line feeds on termination >------------- struct lineFeeds { ~lineFeeds() { std::cout << "\n\n"; } } cosmetic; //----< demonstration of move construction >------------------------------- Test demoFunc() { Test demo("function demo's temporary Test"); showLine(demo.name(), __LINE__, __FUNCSIG__); return demo; } //----< test stub >-------------------------------------------------------- #include int main() { using Helper = UtilityHelpers::Utilities; Helper::title("Demonstrate Test Class"); showLine("-- promotion construction of Test Fred", __LINE__, __FUNCSIG__); Test t("Fred"); // named construction showLine("-- copy construction of Test Fred", __LINE__, __FUNCSIG__); Test t1 = t; // copy construction showLine("-- call demoFunc()", __LINE__, __FUNCSIG__); Test t2 = demoFunc(); // move construction showLine("-- void construction of unnamed Test", __LINE__, __FUNCSIG__); Test t3; showLine("-- assignment of Test Fred", __LINE__, __FUNCSIG__); t3 = t1; // copy assignment showLine("-- assignment of temporary test", __LINE__, __FUNCSIG__); t3 = Test(); // move assignment from temporary std::cout << "\n"; t1.name() = "t1"; t2.name() = "t2"; t3.name() = "t3"; Helper::title("Creating initialized std::vector of Tests"); showLine("-- initialize vector with copies of t1 & t2, and move of t3", __LINE__, __FUNCSIG__); std::vector vt{ t1, t2, std::move(t3) }; for (auto& e : vt) { e.say(); } std::cout << "\n"; Helper::title("Testing push_backs"); showLine("-- promotion construction of t4", __LINE__, __FUNCSIG__); Test t4("t4"); showLine("-- promotion construction of t5", __LINE__, __FUNCSIG__); Test t5("t5"); showLine("-- push_back of t4", __LINE__, __FUNCSIG__); vt.push_back(t4); showLine("-- push_back of std::move(t5)", __LINE__, __FUNCSIG__); vt.push_back(std::move(t5)); for (auto& e : vt) { e.say(); } std::cout << "\n"; Helper::title("Creating vector of smart pointers"); /* * - unique_ptr is a smart pointer to an instance t of type T * - it assumes it is the only reference to t and that t is stored on the native heap * - since it represents unique ownership, it cannot be copied or assigned, only moved * - when it goes out of scope, either through a normal exit from the scope where it was defined * or because an exception was thrown, it calls delete on its iternal pointer to t */ showLine("-- attach unique_ptr sp1 to new Test t6", __LINE__, __FUNCSIG__); std::unique_ptr sp1(new Test("t6")); showLine("-- attach unique_ptr sp2 to new Test t7", __LINE__, __FUNCSIG__); std::unique_ptr sp2(new Test("t7")); showLine("-- create vector of these unique_ptrs", __LINE__, __FUNCSIG__); std::vector> vp; showLine("-- push_back std::move(sp1)", __LINE__, __FUNCSIG__); vp.push_back(std::move(sp1)); showLine("-- push_back std::move(sp2)", __LINE__, __FUNCSIG__); vp.push_back(std::move(sp2)); ///////////////////////////////////////////////////////////////////////// // The line below doesn't work. Initializer_lists are constant so // you can copy but can't move out of them. Unique_ptr is moveable but // not copyable so you have to use push_back // // std::vector> vp { std::move(sp1), std::move(sp2) }; // // Resetting sp2 does not reset the vector vp's unique_ptr. // Instead, it is resetting the now invalid sp2 in main to a new valid Test instance, t8. showLine("-- reset sp2 to new Test(t8)", __LINE__, __FUNCSIG__); sp2.reset(new Test("t8")); // re-initializes sp2 to point to t8, original object was moved into vector so nothing to delete showLine("-- reset sp2 to new Test(t9)", __LINE__, __FUNCSIG__); sp2.reset(new Test("t9")); // re-initializes sp2 to point to t9 then deletes t8 for (auto& p : vp) { p->say(); } std::cout << "\n"; Helper::title("Done with testing"); }