কেন # অন্তর্ভুক্ত <স্ট্রিং> এখানে স্ট্যাক ওভারফ্লো ত্রুটি রোধ করছে?


121

এটি আমার নমুনা কোড:

#include <iostream>
#include <string>
using namespace std;

class MyClass
{
    string figName;
public:
    MyClass(const string& s)
    {
        figName = s;
    }

    const string& getName() const
    {
        return figName;
    }
};

ostream& operator<<(ostream& ausgabe, const MyClass& f)
{
    ausgabe << f.getName();
    return ausgabe;
}

int main()
{
    MyClass f1("Hello");
    cout << f1;
    return 0;
}

যদি আমি মন্তব্য করি তবে আমার #include <string>কোনও সংকলক ত্রুটি না পেয়ে আমি অনুমান করি কারণ এটি এক ধরণের মাধ্যমে অন্তর্ভুক্ত রয়েছে #include <iostream>। যদি আমি মাইক্রোসফ্ট ভিএসে "ডান ক্লিক করুন -> সংজ্ঞাতে যান" তারা উভয়েই xstringফাইলে একই লাইনে নির্দেশ করে :

typedef basic_string<char, char_traits<char>, allocator<char> >
    string;

তবে আমি যখন আমার প্রোগ্রামটি চালাচ্ছি, তখন আমি একটি ব্যতিক্রম ত্রুটি পেয়েছি:

অপারেটর স্ট্রিং.এক্সে 0x77846B6E (ntdll.dll): 0xC00000FD: স্ট্যাক ওভারফ্লো (প্যারামিটার: 0x00000001, 0x01202FC4)

মন্তব্য করার সময় কেন আমি রানটাইম ত্রুটি পেতে পারি তার কোনও ধারণা #include <string>? আমি ভিএস 2013 এক্সপ্রেস ব্যবহার করছি।


4
Godশ্বরের অনুগ্রহে জি সি সি তে নিখুঁতভাবে কাজ করা, আইডোন
ডাইওয়াইসিএফ

আপনি কি ভিজ্যুয়াল সি ++ সহ ভিজ্যুয়াল স্টুডিও চেষ্টা করেছেন এবং মন্তব্যে <স্ট্রিং> অন্তর্ভুক্ত করেছেন?
বায়ুবাহিত

1
@cbuchart: যদিও ইতিমধ্যে প্রশ্নের উত্তর দেওয়া হয়েছিল, আমি মনে করি এটি একটি জটিল যথেষ্ট বিষয় যা বিভিন্ন কথায় দ্বিতীয় উত্তর দেওয়া মূল্যবান। আমি আপনার দুর্দান্ত উত্তরটি মুছে ফেলার জন্য ভোট দিয়েছি।
হালকা ঘোড়দৌড়

5
@ রাস্লান: কার্যকরভাবে, তারা হয়। এটি বলা #include<iostream>এবং এটি <string>উভয়ই অন্তর্ভুক্ত থাকতে পারে <common/stringimpl.h>
এমসাল্টাররা

3
ভিজুয়াল স্টুডিও 2015-এ, আপনি ...\main.cpp(23) : warning C4717: 'operator<<': recursive on all control paths, function will cause runtime stack overflowএই লাইনটি চালানোর সাথে সতর্কতা cl /EHsc main.cpp /Fetest.exe
পেয়েছেন

উত্তর:


161

সত্যই, খুব আকর্ষণীয় আচরণ।

মন্তব্য করার সময় কেন আমি রানটাইম ত্রুটি করি তা সম্পর্কে কোনও ধারণা #include <string>

এমএস ভিসি ++ সংকলক সহ ত্রুটি ঘটে কারণ আপনি এটি না করলে আপনি এর জন্য সংজ্ঞা দেন #include <string>নাoperator<<std::string

সংকলক যখন সংকলন করার চেষ্টা করে তখন এটি ausgabe << f.getName();একটি operator<<সংজ্ঞায়িত সন্ধান করে std::string। যেহেতু এটি সংজ্ঞায়িত হয়নি, সংকলক বিকল্পগুলির সন্ধান করে। এর জন্য একটি operator<<সংজ্ঞায়িত রয়েছে MyClassএবং সংকলক এটি ব্যবহার করার চেষ্টা করে এবং এটি ব্যবহার করতে এটি রূপান্তর std::stringকরতে হয় MyClassএবং ঠিক MyClassএটি ঘটে কারণ একটি স্পষ্টত নির্মাতা নির্মাণকারী নেই! সুতরাং, সংকলকটি আপনার একটি নতুন উদাহরণ তৈরি করে শেষ করে MyClassএটি আবার আপনার আউটপুট প্রবাহে প্রবাহিত করার চেষ্টা করে। এটি একটি অন্তহীন পুনরাবৃত্তির ফলাফল:

 start:
     operator<<(MyClass) -> 
         MyClass::MyClass(MyClass::getName()) -> 
             operator<<(MyClass) -> ... goto start;

ত্রুটি এড়ানোর জন্য আপনাকে #include <string>নিশ্চিত করতে হবে যে এর জন্য কোনও operator<<সংজ্ঞা দেওয়া আছে std::string। এছাড়াও MyClassএই ধরণের অপ্রত্যাশিত রূপান্তর এড়াতে আপনার নির্মাণকারীর স্পষ্ট করা উচিত । প্রজ্ঞার বিধি: নির্মাতারা রূপান্তর এড়াতে যদি কেবল একটি যুক্তি গ্রহণ করেন তবে নির্মাতাকে স্পষ্ট করুন:

class MyClass
{
    string figName;
public:
    explicit MyClass(const string& s) // <<-- avoid implicit conversion
    {
        figName = s;
    }

    const string& getName() const
    {
        return figName;
    }
};

দেখে মনে হচ্ছে operator<<জন্য std::stringশুধুমাত্র সংজ্ঞায়িত পায় যখন <string>(এমএস কম্পাইলার সহ) এবং সেই সব প্রনয়ন জন্য অন্তর্ভুক্ত করা হয়েছে, তবে আপনি কিছুটা অপ্রত্যাশিত আচরণের যেমন পেতে operator<<জন্য যাও recursively নামক হচ্ছে MyClassপরিবর্তে কলিং operator<<জন্য std::string

তার মানে কি #include <iostream>স্ট্রিংয়ের মাধ্যমে কেবল আংশিকভাবে অন্তর্ভুক্ত করা হয়েছে?

না, স্ট্রিং পুরোপুরি অন্তর্ভুক্ত রয়েছে, অন্যথায় আপনি এটি ব্যবহার করতে সক্ষম হবেন না।


19
@ বায়ারবর্ন - এটি "ভিজ্যুয়াল সি ++ নির্দিষ্ট সমস্যা" নয়, তবে আপনি যখন সঠিক শিরোনামটি অন্তর্ভুক্ত করবেন না তখন কী ঘটতে পারে। যখন ব্যবহার std::stringএকটি ছাড়া #include<string>সব ধরনের জিনিস ঘটতে পারে, একটি কম্পাইল সময় ত্রুটি সীমাবদ্ধ নয়। ভুল ফাংশন বা অপারেটর কল করা দৃশ্যত অন্য বিকল্প।
বো পারসন

15
ঠিক আছে, এটি "ভুল ফাংশন বা অপারেটরকে কল করছে না"; সংকলক ঠিক তাই করছে যা আপনি এটি করতে বলেছেন। আপনি কেবল এটি জানেন না যে আপনি এটি করতে বলছেন;)
অরবিটে

18
সম্পর্কিত শিরোনাম ফাইলটি অন্তর্ভুক্ত না করে কোনও ধরণ ব্যবহার করা একটি বাগ is সময়কাল। বাস্তবায়ন কি ত্রুটি চিহ্নিত করা সহজ করে তুলতে পারে? অবশ্যই। তবে এটি বাস্তবায়নের ক্ষেত্রে কোনও "সমস্যা" নয় , আপনার লেখা কোডটিতে এটি একটি সমস্যা।
কোডি গ্রে

4
স্ট্যান্ডার্ড লাইব্রেরিগুলি টোকেনগুলি অন্তর্ভুক্ত করতে পারবেন যা তাদের মধ্যে স্ট্যান্ডের অন্য কোথাও সংজ্ঞায়িত করা হয়েছে এবং যদি তারা একটি টোকেন সংজ্ঞায়িত করে তবে পুরো শিরোনামটি অন্তর্ভুক্ত করার প্রয়োজন হয় না।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

5
সংকলক এবং / অথবা স্ট্যান্ডার্ড লাইব্রেরি তাদের সাহায্য করার জন্য আরও কাজ করা উচিত বলে বিতর্ক করে যে সি ++ প্রোগ্রামারদের একগুচ্ছটি দেখে কিছুটা হাস্যকর। বাস্তবায়নটি এখানে তার অধিকারগুলির মধ্যে যথাযথভাবে রয়েছে, মান অনুসারে, বহুবার নির্দেশিত হয়েছে। প্রোগ্রামারটির জন্য এটি আরও স্পষ্ট করতে "কৌশল" ব্যবহার করা যেতে পারে? অবশ্যই, তবে আমরা জাভাতে কোডও লিখতে পারি এবং এই সমস্যাটি পুরোপুরি এড়াতে পারি। কেন এমএসভিসি এর অভ্যন্তরীণ সহায়কদের দৃশ্যমান করবে? একটি শিরোনাম কেন এটির প্রয়োজন হয় না এমন একগুচ্ছ নির্ভরতা টেনে আনতে হবে? যে ভাষা পুরো চেতনা লঙ্ঘন!
কোডি গ্রে

35

সমস্যাটি হ'ল আপনার কোডটি একটি অসীম পুনরাবৃত্তি করছে। std::string( std::ostream& operator<<(std::ostream&, const std::string&)) এর জন্য স্ট্রিমিং অপারেটরটি <string>শিরোনাম ফাইলটিতে ঘোষিত হয় , যদিও std::stringনিজেই অন্যান্য শিরোলেখ ফাইলটিতে ঘোষিত হয় (উভয় <iostream>এবং উভয়ই অন্তর্ভুক্ত <string>)।

আপনি যখন <string>সংকলকটি অন্তর্ভুক্ত করবেন না তখন সংকলনের কোনও উপায় অনুসন্ধান করার চেষ্টা করে ausgabe << f.getName();

এটি ঘটে যে আপনি স্ট্রিমিং অপারেটর MyClassএবং কনস্ট্রাক্টর উভয়কেই সংজ্ঞায়িত করেছেন যা একজনকে স্বীকার করে std::string, তাই সংকলক এটি পুনরায় সংবেদনশীল কল তৈরি করে (অন্তর্ভুক্ত নির্মাণের মাধ্যমে ) ব্যবহার করে ।

যদি আপনি explicitআপনার কনস্ট্রাক্টর ( explicit MyClass(const std::string& s)) ঘোষণা করেন তবে আপনার কোডটি আর সংকলন করবে না, যেহেতু স্ট্রিমিং অপারেটরটির সাথে কল করার কোনও উপায় নেই std::stringএবং আপনাকে <string>শিরোনামটি অন্তর্ভুক্ত করতে বাধ্য হবে ।

সম্পাদনা

আমার পরীক্ষার পরিবেশটি ভিএস ২০১০, এবং সতর্কতার স্তরের 1 ( /W1) থেকে শুরু করে এটি আপনাকে সমস্যার বিষয়ে সতর্ক করে:

সতর্কতা C4717: 'অপারেটর <<': সমস্ত নিয়ন্ত্রণের পথে পুনরাবৃত্তি, ফাংশন রানটাইম স্ট্যাকের ওভারফ্লো করবে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.